[Spice-commits] 6 commits - server/dcc.c server/dcc.h server/dcc-send.c server/display-channel.c server/display-channel.h server/red-channel.c server/red-channel.h server/red-dispatcher.c server/red-dispatcher.h server/reds.c server/reds.h server/red-worker.c server/spice-qxl.h server/spice-server.syms

Frediano Ziglio fziglio at kemper.freedesktop.org
Tue Feb 9 14:07:31 UTC 2016


 server/dcc-send.c        |   39 +++++++++++++++++++++++
 server/dcc.c             |   79 +++++++++++++++++++++++++++++++++++++++++++++++
 server/dcc.h             |   14 ++++++++
 server/display-channel.c |   34 ++++++++++++++++++++
 server/display-channel.h |    8 ++++
 server/red-channel.c     |   19 +++++++----
 server/red-channel.h     |    2 -
 server/red-dispatcher.c  |   57 +++++++++++++++++++++++++++++++++
 server/red-dispatcher.h  |    2 +
 server/red-worker.c      |   27 ++++++++++++++++
 server/reds.c            |    2 +
 server/reds.h            |    3 +
 server/spice-qxl.h       |   10 +++++
 server/spice-server.syms |    6 +++
 14 files changed, 295 insertions(+), 7 deletions(-)

New commits:
commit 87778643119aa73e6df2dd690f03eb1c39b69cd4
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Feb 9 14:35:06 2016 +0100

    Handle GL_DRAW_DONE
    
    When a client is done with drawing and sends
    SPICE_MSGC_DISPLAY_GL_DRAW_DONE, or when it ends, update the number of
    async counts.
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
    [reduce critical message to a warning; do not reset gl_draw_ongoing
     - Frediano Ziglio]
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/dcc.c b/server/dcc.c
index 6972616..5ccbda1 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -494,6 +494,8 @@ static void dcc_destroy_stream_agents(DisplayChannelClient *dcc)
 
 void dcc_stop(DisplayChannelClient *dcc)
 {
+    DisplayChannel *dc = DCC_TO_DC(dcc);
+
     pixmap_cache_unref(dcc->pixmap_cache);
     dcc->pixmap_cache = NULL;
     dcc_release_glz(dcc);
@@ -502,6 +504,10 @@ void dcc_stop(DisplayChannelClient *dcc)
     free(dcc->send_data.free_list.res);
     dcc_destroy_stream_agents(dcc);
     dcc_encoders_free(dcc);
+
+    if (dcc->gl_draw_ongoing) {
+        display_channel_gl_draw_done(dc);
+    }
 }
 
 void dcc_stream_agent_clip(DisplayChannelClient* dcc, StreamAgent *agent)
@@ -1391,6 +1397,22 @@ static int dcc_handle_preferred_compression(DisplayChannelClient *dcc,
     return TRUE;
 }
 
+static int dcc_handle_gl_draw_done(DisplayChannelClient *dcc)
+{
+    DisplayChannel *display = DCC_TO_DC(dcc);
+
+    if (G_UNLIKELY(!dcc->gl_draw_ongoing)) {
+        g_warning("unexpected DRAW_DONE received\n");
+        /* close client connection */
+        return FALSE;
+    }
+
+    dcc->gl_draw_ongoing = FALSE;
+    display_channel_gl_draw_done(display);
+
+    return TRUE;
+}
+
 int dcc_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type, void *msg)
 {
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
@@ -1403,6 +1425,8 @@ int dcc_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type, void
     case SPICE_MSGC_DISPLAY_PREFERRED_COMPRESSION:
         return dcc_handle_preferred_compression(dcc,
             (SpiceMsgcDisplayPreferredCompression *)msg);
+    case SPICE_MSGC_DISPLAY_GL_DRAW_DONE:
+        return dcc_handle_gl_draw_done(dcc);
     default:
         return red_channel_client_handle_message(rcc, size, type, msg);
     }
diff --git a/server/display-channel.c b/server/display-channel.c
index 936c74a..b4f7ede 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -2178,3 +2178,8 @@ void display_channel_gl_draw(DisplayChannel *display, SpiceMsgDisplayGlDraw *dra
     num = red_channel_pipes_new_add_push(RED_CHANNEL(display), dcc_gl_draw_item_new, draw);
     set_gl_draw_async_count(display, num);
 }
+
+void display_channel_gl_draw_done(DisplayChannel *display)
+{
+    set_gl_draw_async_count(display, display->gl_draw_async_count - 1);
+}
diff --git a/server/display-channel.h b/server/display-channel.h
index 3d2a465..82fd663 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -313,6 +313,7 @@ void                       display_channel_update_compression        (DisplayCha
 void                       display_channel_gl_scanout                (DisplayChannel *display);
 void                       display_channel_gl_draw                   (DisplayChannel *display,
                                                                       SpiceMsgDisplayGlDraw *draw);
+void                       display_channel_gl_draw_done              (DisplayChannel *display);
 
 static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
 {
commit 381dc93ec0fd126992f5959305ded00987e10847
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Feb 9 14:35:05 2016 +0100

    Handle GL_DRAW messages
    
    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>

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);
 }
 
 
commit 5881b40ebdbcde4a09b0ec0ec47b9b2439d5f61e
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Feb 9 14:35:04 2016 +0100

    Send current GL scanout to new client
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>

diff --git a/server/dcc.c b/server/dcc.c
index eb63ce6..58ae55c 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -445,6 +445,7 @@ void dcc_start(DisplayChannelClient *dcc)
 {
     DisplayChannel *display = DCC_TO_DC(dcc);
     RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc);
+    QXLInstance *qxl = red_worker_get_qxl(COMMON_CHANNEL(display)->worker);
 
     red_channel_client_push_set_ack(RED_CHANNEL_CLIENT(dcc));
 
@@ -464,6 +465,16 @@ void dcc_start(DisplayChannelClient *dcc)
         red_pipe_add_verb(rcc, SPICE_MSG_DISPLAY_MARK);
         dcc_create_all_streams(dcc);
     }
+
+    if (qxl->st->scanout.drm_dma_buf_fd >= 0) {
+        if (reds_stream_is_plain_unix(rcc->stream) &&
+            red_channel_client_test_remote_cap(rcc, SPICE_DISPLAY_CAP_GL_SCANOUT)) {
+            red_channel_client_pipe_add(rcc, dcc_gl_scanout_item_new(rcc, NULL, 0));
+            dcc_push_monitors_config(dcc);
+        } else {
+            spice_printerr("FIXME: GL not supported on this kind of connection");
+        }
+    }
 }
 
 static void dcc_destroy_stream_agents(DisplayChannelClient *dcc)
commit 7a06efde1cc75482defea0a84b473b1c6b65afdd
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Feb 9 14:35:03 2016 +0100

    Handle GL_SCANOUT messages
    
    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>

diff --git a/server/dcc-send.c b/server/dcc-send.c
index 3cb50ba..a9cc19c 100644
--- a/server/dcc-send.c
+++ b/server/dcc-send.c
@@ -2299,6 +2299,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->drm_dma_buf_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);
@@ -2410,6 +2432,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 bf692f8..eb63ce6 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 &item->base;
+}
+
 void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
 {
     DisplayChannel *display;
@@ -1527,6 +1546,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;
@@ -1601,6 +1621,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 f715792..4ef6073 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 f0d133a..bd8098e 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -2149,3 +2149,8 @@ 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-dispatcher.c b/server/red-dispatcher.c
index 009c377..26a153e 100644
--- a/server/red-dispatcher.c
+++ b/server/red-dispatcher.c
@@ -970,6 +970,8 @@ void spice_qxl_gl_scanout(QXLInstance *qxl,
     spice_return_if_fail(qxl != NULL);
     spice_return_if_fail(qxl->st->gl_draw_async == NULL);
 
+    pthread_mutex_lock(&qxl->st->scanout_mutex);
+
     if (qxl->st->scanout.drm_dma_buf_fd != -1) {
         close(qxl->st->scanout.drm_dma_buf_fd);
     }
@@ -982,6 +984,12 @@ void spice_qxl_gl_scanout(QXLInstance *qxl,
         .stride = stride,
         .drm_fourcc_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 d99695d..cc60c10 100644
--- a/server/red-dispatcher.h
+++ b/server/red-dispatcher.h
@@ -88,6 +88,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 e70c9df..76ac41c 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -1159,6 +1159,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;
@@ -1396,6 +1404,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 5f370c0..a46c194 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -3185,6 +3185,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.drm_dma_buf_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 3182382..f141043 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -36,6 +36,7 @@ extern RedsState *reds;
 struct QXLState {
     QXLInterface          *qif;
     struct RedDispatcher  *dispatcher;
+    pthread_mutex_t scanout_mutex;
     SpiceMsgDisplayGlScanoutUnix scanout;
     struct AsyncCommand *gl_draw_async;
 };
commit ebf461b8e699536a600a15d600dc9a28e865cb90
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Feb 9 14:35:02 2016 +0100

    Add new spice-gl stubs API
    
    - spice_qxl_gl_scanout() to take the current scanout
    
    - spice_qxl_gl_draw_async() to draw the scanout, is like other Spice async
      functions, it takes a cookie and will return in the
      QXLInterface.async_complete()
    
    Two new fields are also added to QXLState, in order to save the current
    scanout, and the pending async.
    
    A scanout can't be updated if there are pending draw atm. Discarding
    outdated draws is left as a future improvement to allow updating the
    scanout without waiting for draw async to be done.
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
    [make QXL function names more coherent - Frediano Ziglio]
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/red-dispatcher.c b/server/red-dispatcher.c
index 374d5a9..009c377 100644
--- a/server/red-dispatcher.c
+++ b/server/red-dispatcher.c
@@ -960,6 +960,41 @@ void spice_qxl_driver_unload(QXLInstance *instance)
     red_dispatcher_driver_unload(instance->st->dispatcher);
 }
 
+SPICE_GNUC_VISIBLE
+void spice_qxl_gl_scanout(QXLInstance *qxl,
+                          int fd,
+                          uint32_t width, uint32_t height,
+                          uint32_t stride, uint32_t format,
+                          int y_0_top)
+{
+    spice_return_if_fail(qxl != NULL);
+    spice_return_if_fail(qxl->st->gl_draw_async == NULL);
+
+    if (qxl->st->scanout.drm_dma_buf_fd != -1) {
+        close(qxl->st->scanout.drm_dma_buf_fd);
+    }
+
+    qxl->st->scanout = (SpiceMsgDisplayGlScanoutUnix) {
+        .flags = y_0_top ? SPICE_GL_SCANOUT_FLAGS_Y0TOP : 0,
+        .drm_dma_buf_fd = fd,
+        .width = width,
+        .height = height,
+        .stride = stride,
+        .drm_fourcc_format = format
+    };
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_gl_draw_async(QXLInstance *qxl,
+                             uint32_t x, uint32_t y,
+                             uint32_t w, uint32_t h,
+                             uint64_t cookie)
+{
+    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);
+}
+
 void red_dispatcher_async_complete(struct RedDispatcher *dispatcher,
                                    AsyncCommand *async_command)
 {
diff --git a/server/reds.c b/server/reds.c
index 7ccf0f1..5f370c0 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -3185,6 +3185,7 @@ SPICE_GNUC_VISIBLE int spice_server_add_interface(SpiceServer *s,
 
         qxl = SPICE_CONTAINEROF(sin, QXLInstance, base);
         qxl->st = spice_new0(QXLState, 1);
+        qxl->st->scanout.drm_dma_buf_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 8ff4491..3182382 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -36,6 +36,8 @@ extern RedsState *reds;
 struct QXLState {
     QXLInterface          *qif;
     struct RedDispatcher  *dispatcher;
+    SpiceMsgDisplayGlScanoutUnix scanout;
+    struct AsyncCommand *gl_draw_async;
 };
 
 struct TunnelWorker;
diff --git a/server/spice-qxl.h b/server/spice-qxl.h
index 3faa3a4..b8910bf 100644
--- a/server/spice-qxl.h
+++ b/server/spice-qxl.h
@@ -104,6 +104,16 @@ void spice_qxl_driver_unload(QXLInstance *instance);
 /* since spice 0.12.6 */
 void spice_qxl_set_max_monitors(QXLInstance *instance,
                                 unsigned int max_monitors);
+/* since spice 0.13.1 */
+void spice_qxl_gl_scanout(QXLInstance *instance,
+                          int fd,
+                          uint32_t width, uint32_t height,
+                          uint32_t stride, uint32_t format,
+                          int y_0_top);
+void spice_qxl_gl_draw_async(QXLInstance *instance,
+                             uint32_t x, uint32_t y,
+                             uint32_t w, uint32_t h,
+                             uint64_t cookie);
 
 typedef struct QXLDrawArea {
     uint8_t *buf;
diff --git a/server/spice-server.syms b/server/spice-server.syms
index 4137546..7987d51 100644
--- a/server/spice-server.syms
+++ b/server/spice-server.syms
@@ -167,3 +167,9 @@ SPICE_SERVER_0.12.7 {
 global:
     spice_server_set_keepalive_timeout;
 } SPICE_SERVER_0.12.6;
+
+SPICE_SERVER_0.13.1 {
+global:
+    spice_qxl_gl_scanout;
+    spice_qxl_gl_draw_async;
+} SPICE_SERVER_0.12.7;
commit 9766619dfffaebc82728624e6d0a0c3083ee2906
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Feb 9 14:35:01 2016 +0100

    red-channel: return number of created pipe items
    
    This is useful in the following patches to count the number of replies
    to wait for.
    
    Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>

diff --git a/server/red-channel.c b/server/red-channel.c
index 4bc2faa..f3a1cea 100644
--- a/server/red-channel.c
+++ b/server/red-channel.c
@@ -2245,15 +2245,17 @@ typedef int (*rcc_item_cond_t)(RedChannelClient *rcc, PipeItem *item);
  * @creator: a callback to create pipe item (not null)
  * @data: the data to pass to the creator
  * @pipe_add: a callback to add non-null pipe items (not null)
+ *
+ * Returns: the number of added items
  **/
-static void red_channel_pipes_create_batch(RedChannel *channel,
+static int red_channel_pipes_create_batch(RedChannel *channel,
                                 new_pipe_item_t creator, void *data,
                                 rcc_item_t pipe_add)
 {
     RingItem *link, *next;
     RedChannelClient *rcc;
     PipeItem *item;
-    int num = 0;
+    int num = 0, n = 0;
 
     spice_assert(creator != NULL);
     spice_assert(pipe_add != NULL);
@@ -2263,16 +2265,21 @@ static void red_channel_pipes_create_batch(RedChannel *channel,
         item = (*creator)(rcc, data, num++);
         if (item) {
             (*pipe_add)(rcc, item);
+            n++;
         }
     }
+
+    return n;
 }
 
-void red_channel_pipes_new_add_push(RedChannel *channel,
-                              new_pipe_item_t creator, void *data)
+int red_channel_pipes_new_add_push(RedChannel *channel,
+                                   new_pipe_item_t creator, void *data)
 {
-    red_channel_pipes_create_batch(channel, creator, data,
-                                     red_channel_client_pipe_add);
+    int n = red_channel_pipes_create_batch(channel, creator, data,
+                                           red_channel_client_pipe_add);
     red_channel_push(channel);
+
+    return n;
 }
 
 void red_channel_pipes_new_add(RedChannel *channel, new_pipe_item_t creator, void *data)
diff --git a/server/red-channel.h b/server/red-channel.h
index 791bc5b..fbb93b7 100644
--- a/server/red-channel.h
+++ b/server/red-channel.h
@@ -478,7 +478,7 @@ void red_channel_pipe_item_init(RedChannel *channel, PipeItem *item, int type);
 
 // helper to push a new item to all channels
 typedef PipeItem *(*new_pipe_item_t)(RedChannelClient *rcc, void *data, int num);
-void red_channel_pipes_new_add_push(RedChannel *channel, new_pipe_item_t creator, void *data);
+int red_channel_pipes_new_add_push(RedChannel *channel, new_pipe_item_t creator, void *data);
 void red_channel_pipes_new_add(RedChannel *channel, new_pipe_item_t creator, void *data);
 void red_channel_pipes_new_add_tail(RedChannel *channel, new_pipe_item_t creator, void *data);
 


More information about the Spice-commits mailing list