[Spice-devel] [PATCH spice 15/18] Handle GL_SCANOUT messages

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


Go through dispatcher and marshall scanout message. Since the marshaller
and the QXL state are manipulated from different threads, add a mutex to
protect the current scanout.

Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
---
 server/dcc-send.c        | 25 +++++++++++++++++++++++++
 server/dcc.c             | 21 +++++++++++++++++++++
 server/dcc.h             |  6 ++++++
 server/display-channel.c |  6 ++++++
 server/display-channel.h |  2 ++
 server/red-channel.h     |  2 ++
 server/red-dispatcher.c  |  8 ++++++++
 server/red-dispatcher.h  |  1 +
 server/red-worker.c      | 13 +++++++++++++
 server/reds.c            |  1 +
 server/reds.h            |  1 +
 11 files changed, 86 insertions(+)

diff --git a/server/dcc-send.c b/server/dcc-send.c
index c3f79ef..8cc2dda 100644
--- a/server/dcc-send.c
+++ b/server/dcc-send.c
@@ -2339,6 +2339,28 @@ static void marshall_stream_activate_report(RedChannelClient *rcc,
     spice_marshall_msg_display_stream_activate_report(base_marshaller, &msg);
 }
 
+static void marshall_gl_scanout(RedChannelClient *rcc,
+                                SpiceMarshaller *m,
+                                PipeItem *item)
+{
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    DisplayChannel *display_channel = DCC_TO_DC(dcc);
+    RedWorker *worker = display_channel->common.worker;
+    QXLInstance* qxl = red_worker_get_qxl(worker);
+    SpiceMsgDisplayGlScanoutUnix *so = &qxl->st->scanout;
+
+    pthread_mutex_lock(&qxl->st->scanout_mutex);
+
+    if (so->fd == -1)
+        goto end;
+
+    red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_GL_SCANOUT_UNIX, NULL);
+    spice_marshall_msg_display_gl_scanout_unix(m, so);
+
+end:
+    pthread_mutex_unlock(&qxl->st->scanout_mutex);
+}
+
 static void begin_send_message(RedChannelClient *rcc)
 {
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -2450,6 +2472,9 @@ void dcc_send_item(DisplayChannelClient *dcc, PipeItem *pipe_item)
         marshall_stream_activate_report(rcc, m, report_item->stream_id);
         break;
     }
+    case PIPE_ITEM_TYPE_GL_SCANOUT:
+        marshall_gl_scanout(rcc, m, pipe_item);
+        break;
     default:
         spice_warn_if_reached();
     }
diff --git a/server/dcc.c b/server/dcc.c
index b2ee7a6..c56ceb6 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -556,6 +556,25 @@ static SurfaceDestroyItem *surface_destroy_item_new(RedChannel *channel,
     return destroy;
 }
 
+PipeItem *dcc_gl_scanout_item_new(RedChannelClient *rcc, void *data, int num)
+{
+    GlScanoutUnixItem *item = spice_new(GlScanoutUnixItem, 1);
+    spice_return_val_if_fail(item != NULL, NULL);
+
+    /* FIXME: on !unix peer, start streaming with a video codec */
+    if (!reds_stream_is_plain_unix(rcc->stream) ||
+        !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;
+    }
+
+    red_channel_pipe_item_init(rcc->channel, &item->base,
+                               PIPE_ITEM_TYPE_GL_SCANOUT);
+
+    return PIPE_ITEM(item);
+}
+
 void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
 {
     DisplayChannel *display;
@@ -1555,6 +1574,7 @@ static void release_item_after_push(DisplayChannelClient *dcc, PipeItem *item)
     case PIPE_ITEM_TYPE_IMAGE:
         image_item_unref((ImageItem *)item);
         break;
+    case PIPE_ITEM_TYPE_GL_SCANOUT:
     case PIPE_ITEM_TYPE_VERB:
         free(item);
         break;
@@ -1629,6 +1649,7 @@ static void release_item_before_push(DisplayChannelClient *dcc, PipeItem *item)
     case PIPE_ITEM_TYPE_PIXMAP_RESET:
     case PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE:
     case PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT:
+    case PIPE_ITEM_TYPE_GL_SCANOUT:
         free(item);
         break;
     default:
diff --git a/server/dcc.h b/server/dcc.h
index 2a12226..22d236e 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -124,6 +124,10 @@ typedef struct SurfaceCreateItem {
     PipeItem pipe_item;
 } SurfaceCreateItem;
 
+typedef struct GlScanoutUnixItem {
+    PipeItem base;
+} GlScanoutUnixItem;
+
 typedef struct ImageItem {
     PipeItem link;
     int refs;
@@ -207,6 +211,8 @@ int                        dcc_clear_surface_drawables_from_pipe     (DisplayCha
                                                                       int wait_if_used);
 int                        dcc_drawable_is_in_pipe                   (DisplayChannelClient *dcc,
                                                                       Drawable *drawable);
+PipeItem *                 dcc_gl_scanout_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 ec4ca10..1f8f5af 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -2149,3 +2149,9 @@ void display_channel_update_compression(DisplayChannel *display, DisplayChannelC
     spice_info("jpeg %s", display->enable_jpeg ? "enabled" : "disabled");
     spice_info("zlib-over-glz %s", display->enable_zlib_glz_wrap ? "enabled" : "disabled");
 }
+
+void display_channel_gl_scanout(DisplayChannel *display)
+{
+    red_channel_pipes_new_add_push(RED_CHANNEL(display), dcc_gl_scanout_item_new, NULL);
+}
+
diff --git a/server/display-channel.h b/server/display-channel.h
index bf29cd3..346e61a 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -106,6 +106,7 @@ enum {
     PIPE_ITEM_TYPE_DESTROY_SURFACE,
     PIPE_ITEM_TYPE_MONITORS_CONFIG,
     PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT,
+    PIPE_ITEM_TYPE_GL_SCANOUT,
 };
 
 typedef struct MonitorsConfig {
@@ -306,6 +307,7 @@ void                       display_channel_process_surface_cmd       (DisplayCha
                                                                       int loadvm);
 void                       display_channel_update_compression        (DisplayChannel *display,
                                                                       DisplayChannelClient *dcc);
+void                       display_channel_gl_scanout                (DisplayChannel *display);
 
 static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
 {
diff --git a/server/red-channel.h b/server/red-channel.h
index aa06416..eef22f1 100644
--- a/server/red-channel.h
+++ b/server/red-channel.h
@@ -157,6 +157,8 @@ static inline int pipe_item_is_linked(PipeItem *item)
     return ring_item_is_linked(&item->link);
 }
 
+#define PIPE_ITEM(item) ((PipeItem*)(item))
+
 typedef uint8_t *(*channel_alloc_msg_recv_buf_proc)(RedChannelClient *channel,
                                                     uint16_t type, uint32_t size);
 typedef int (*channel_handle_parsed_proc)(RedChannelClient *rcc, uint32_t size, uint16_t type,
diff --git a/server/red-dispatcher.c b/server/red-dispatcher.c
index a1e4e1e..183a0d3 100644
--- a/server/red-dispatcher.c
+++ b/server/red-dispatcher.c
@@ -968,6 +968,8 @@ void spice_gl_scanout(QXLInstance *qxl,
 {
     spice_return_if_fail(qxl != NULL);
 
+    pthread_mutex_lock(&qxl->st->scanout_mutex);
+
     if (qxl->st->scanout.fd != -1) {
         close(qxl->st->scanout.fd);
     }
@@ -980,6 +982,12 @@ void spice_gl_scanout(QXLInstance *qxl,
         .stride = stride,
         .format = format
     };
+
+    pthread_mutex_unlock(&qxl->st->scanout_mutex);
+
+    /* FIXME: find a way to coallesce all pending SCANOUTs */
+    dispatcher_send_message(&qxl->st->dispatcher->dispatcher,
+                            RED_WORKER_MESSAGE_GL_SCANOUT, NULL);
 }
 
 SPICE_GNUC_VISIBLE
diff --git a/server/red-dispatcher.h b/server/red-dispatcher.h
index 7aabe44..e4ba79f 100644
--- a/server/red-dispatcher.h
+++ b/server/red-dispatcher.h
@@ -86,6 +86,7 @@ enum {
 
     RED_WORKER_MESSAGE_MONITORS_CONFIG_ASYNC,
     RED_WORKER_MESSAGE_DRIVER_UNLOAD,
+    RED_WORKER_MESSAGE_GL_SCANOUT,
 
     RED_WORKER_MESSAGE_COUNT // LAST
 };
diff --git a/server/red-worker.c b/server/red-worker.c
index dfaf4ba..7005166 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -1286,6 +1286,14 @@ static void handle_dev_driver_unload(void *opaque, void *payload)
     worker->driver_cap_monitors_config = 0;
 }
 
+static
+void handle_dev_gl_scanout(void *opaque, void *payload)
+{
+    RedWorker *worker = opaque;
+
+    display_channel_gl_scanout(worker->display_channel);
+}
+
 static int loadvm_command(RedWorker *worker, QXLCommandExt *ext)
 {
     RedCursorCmd *cursor_cmd;
@@ -1523,6 +1531,11 @@ static void register_callbacks(Dispatcher *dispatcher)
                                 handle_dev_driver_unload,
                                 sizeof(RedWorkerMessageDriverUnload),
                                 DISPATCHER_NONE);
+    dispatcher_register_handler(dispatcher,
+                                RED_WORKER_MESSAGE_GL_SCANOUT,
+                                handle_dev_gl_scanout,
+                                0,
+                                DISPATCHER_NONE);
 }
 
 
diff --git a/server/reds.c b/server/reds.c
index fafa135..e7edaff 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -3155,6 +3155,7 @@ SPICE_GNUC_VISIBLE int spice_server_add_interface(SpiceServer *s,
 
         qxl = SPICE_CONTAINEROF(sin, QXLInstance, base);
         qxl->st = spice_new0(QXLState, 1);
+        pthread_mutex_init(&qxl->st->scanout_mutex, NULL);
         qxl->st->scanout.fd = -1;
         qxl->st->qif = SPICE_CONTAINEROF(interface, QXLInterface, base);
         red_dispatcher_init(qxl);
diff --git a/server/reds.h b/server/reds.h
index 07ad8f9..cffa57f 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -33,6 +33,7 @@
 struct QXLState {
     QXLInterface          *qif;
     struct RedDispatcher  *dispatcher;
+    pthread_mutex_t scanout_mutex;
     SpiceMsgDisplayGlScanoutUnix scanout;
     AsyncCommand *gl_draw_async;
 };
-- 
2.5.0



More information about the Spice-devel mailing list