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@gmail.com>
This commit is contained in:
Marc-André Lureau 2016-02-09 14:35:03 +01:00 committed by Frediano Ziglio
parent ebf461b8e6
commit 7a06efde1c
10 changed files with 83 additions and 0 deletions

View File

@ -2299,6 +2299,28 @@ static void marshall_stream_activate_report(RedChannelClient *rcc,
spice_marshall_msg_display_stream_activate_report(base_marshaller, &msg); 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) static void begin_send_message(RedChannelClient *rcc)
{ {
DisplayChannelClient *dcc = RCC_TO_DCC(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); marshall_stream_activate_report(rcc, m, report_item->stream_id);
break; break;
} }
case PIPE_ITEM_TYPE_GL_SCANOUT:
marshall_gl_scanout(rcc, m, pipe_item);
break;
default: default:
spice_warn_if_reached(); spice_warn_if_reached();
} }

View File

@ -556,6 +556,25 @@ static SurfaceDestroyItem *surface_destroy_item_new(RedChannel *channel,
return destroy; 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) void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
{ {
DisplayChannel *display; DisplayChannel *display;
@ -1527,6 +1546,7 @@ static void release_item_after_push(DisplayChannelClient *dcc, PipeItem *item)
case PIPE_ITEM_TYPE_IMAGE: case PIPE_ITEM_TYPE_IMAGE:
image_item_unref((ImageItem *)item); image_item_unref((ImageItem *)item);
break; break;
case PIPE_ITEM_TYPE_GL_SCANOUT:
case PIPE_ITEM_TYPE_VERB: case PIPE_ITEM_TYPE_VERB:
free(item); free(item);
break; 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_PIXMAP_RESET:
case PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE: case PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE:
case PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT: case PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT:
case PIPE_ITEM_TYPE_GL_SCANOUT:
free(item); free(item);
break; break;
default: default:

View File

@ -124,6 +124,10 @@ typedef struct SurfaceCreateItem {
PipeItem pipe_item; PipeItem pipe_item;
} SurfaceCreateItem; } SurfaceCreateItem;
typedef struct GlScanoutUnixItem {
PipeItem base;
} GlScanoutUnixItem;
typedef struct ImageItem { typedef struct ImageItem {
PipeItem link; PipeItem link;
int refs; int refs;
@ -207,6 +211,8 @@ int dcc_clear_surface_drawables_from_pipe (DisplayCha
int wait_if_used); int wait_if_used);
int dcc_drawable_is_in_pipe (DisplayChannelClient *dcc, int dcc_drawable_is_in_pipe (DisplayChannelClient *dcc,
Drawable *drawable); Drawable *drawable);
PipeItem * dcc_gl_scanout_item_new (RedChannelClient *rcc,
void *data, int num);
typedef struct compress_send_data_t { typedef struct compress_send_data_t {
void* comp_buf; void* comp_buf;

View File

@ -2149,3 +2149,8 @@ void display_channel_update_compression(DisplayChannel *display, DisplayChannelC
spice_info("jpeg %s", display->enable_jpeg ? "enabled" : "disabled"); spice_info("jpeg %s", display->enable_jpeg ? "enabled" : "disabled");
spice_info("zlib-over-glz %s", display->enable_zlib_glz_wrap ? "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);
}

View File

@ -106,6 +106,7 @@ enum {
PIPE_ITEM_TYPE_DESTROY_SURFACE, PIPE_ITEM_TYPE_DESTROY_SURFACE,
PIPE_ITEM_TYPE_MONITORS_CONFIG, PIPE_ITEM_TYPE_MONITORS_CONFIG,
PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT, PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT,
PIPE_ITEM_TYPE_GL_SCANOUT,
}; };
typedef struct MonitorsConfig { typedef struct MonitorsConfig {
@ -306,6 +307,7 @@ void display_channel_process_surface_cmd (DisplayCha
int loadvm); int loadvm);
void display_channel_update_compression (DisplayChannel *display, void display_channel_update_compression (DisplayChannel *display,
DisplayChannelClient *dcc); DisplayChannelClient *dcc);
void display_channel_gl_scanout (DisplayChannel *display);
static inline int validate_surface(DisplayChannel *display, uint32_t surface_id) static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
{ {

View File

@ -970,6 +970,8 @@ void spice_qxl_gl_scanout(QXLInstance *qxl,
spice_return_if_fail(qxl != NULL); spice_return_if_fail(qxl != NULL);
spice_return_if_fail(qxl->st->gl_draw_async == 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) { if (qxl->st->scanout.drm_dma_buf_fd != -1) {
close(qxl->st->scanout.drm_dma_buf_fd); close(qxl->st->scanout.drm_dma_buf_fd);
} }
@ -982,6 +984,12 @@ void spice_qxl_gl_scanout(QXLInstance *qxl,
.stride = stride, .stride = stride,
.drm_fourcc_format = format .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 SPICE_GNUC_VISIBLE

View File

@ -88,6 +88,7 @@ enum {
RED_WORKER_MESSAGE_MONITORS_CONFIG_ASYNC, RED_WORKER_MESSAGE_MONITORS_CONFIG_ASYNC,
RED_WORKER_MESSAGE_DRIVER_UNLOAD, RED_WORKER_MESSAGE_DRIVER_UNLOAD,
RED_WORKER_MESSAGE_GL_SCANOUT,
RED_WORKER_MESSAGE_COUNT // LAST RED_WORKER_MESSAGE_COUNT // LAST
}; };

View File

@ -1159,6 +1159,14 @@ static void handle_dev_driver_unload(void *opaque, void *payload)
worker->driver_cap_monitors_config = 0; 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) static int loadvm_command(RedWorker *worker, QXLCommandExt *ext)
{ {
RedCursorCmd *cursor_cmd; RedCursorCmd *cursor_cmd;
@ -1396,6 +1404,11 @@ static void register_callbacks(Dispatcher *dispatcher)
handle_dev_driver_unload, handle_dev_driver_unload,
sizeof(RedWorkerMessageDriverUnload), sizeof(RedWorkerMessageDriverUnload),
DISPATCHER_NONE); DISPATCHER_NONE);
dispatcher_register_handler(dispatcher,
RED_WORKER_MESSAGE_GL_SCANOUT,
handle_dev_gl_scanout,
0,
DISPATCHER_NONE);
} }

View File

@ -3185,6 +3185,7 @@ SPICE_GNUC_VISIBLE int spice_server_add_interface(SpiceServer *s,
qxl = SPICE_CONTAINEROF(sin, QXLInstance, base); qxl = SPICE_CONTAINEROF(sin, QXLInstance, base);
qxl->st = spice_new0(QXLState, 1); qxl->st = spice_new0(QXLState, 1);
pthread_mutex_init(&qxl->st->scanout_mutex, NULL);
qxl->st->scanout.drm_dma_buf_fd = -1; qxl->st->scanout.drm_dma_buf_fd = -1;
qxl->st->qif = SPICE_CONTAINEROF(interface, QXLInterface, base); qxl->st->qif = SPICE_CONTAINEROF(interface, QXLInterface, base);
red_dispatcher_init(qxl); red_dispatcher_init(qxl);

View File

@ -36,6 +36,7 @@ extern RedsState *reds;
struct QXLState { struct QXLState {
QXLInterface *qif; QXLInterface *qif;
struct RedDispatcher *dispatcher; struct RedDispatcher *dispatcher;
pthread_mutex_t scanout_mutex;
SpiceMsgDisplayGlScanoutUnix scanout; SpiceMsgDisplayGlScanoutUnix scanout;
struct AsyncCommand *gl_draw_async; struct AsyncCommand *gl_draw_async;
}; };