[Spice-devel] [PATCH v3 6/9] Handle GL_SCANOUT messages
Marc-André Lureau
marcandre.lureau at gmail.com
Fri Jan 22 09:14:07 PST 2016
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 | 5 +++++
server/display-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 +
10 files changed, 83 insertions(+)
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 f776f66..6d705fc 100644
--- a/server/red-dispatcher.c
+++ b/server/red-dispatcher.c
@@ -969,6 +969,8 @@ void spice_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);
}
@@ -981,6 +983,12 @@ void spice_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 ad8ba1a..266014d 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -1283,6 +1283,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;
@@ -1520,6 +1528,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 156e653..31f540a 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -3233,6 +3233,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 c1ab878..308edea 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;
};
--
2.5.0
More information about the Spice-devel
mailing list