[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC v2 2/2] spice: Add an option to forward the dmabuf directly to the
From: |
Vivek Kasireddy |
Subject: |
[RFC v2 2/2] spice: Add an option to forward the dmabuf directly to the encoder (v2) |
Date: |
Mon, 23 Jan 2023 00:37:55 -0800 |
This patch adds support for gl=on and port != 0. In other words,
with this option enabled, it should be possible to stream the
content associated with the dmabuf to a remote client.
Here is the flow of things from the Qemu side:
- Call gl_scanout (to update the fd) and gl_draw_async just like
in the local display case.
- Additionally, create an update with the cmd set to QXL_CMD_DRAW
to trigger the creation of a new drawable (associated with the fd)
by the Spice server.
- Wait (or block) until the Encoder is done encoding the content.
- Unblock the pipeline once the async completion cookie is received.
v2:
- Use the existing gl_scanout and gl_draw_async APIs instead of
adding new ones.
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
Cc: Dongwon Kim <dongwon.kim@intel.com>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
---
include/ui/spice-display.h | 1 +
qemu-options.hx | 6 ++-
ui/spice-core.c | 22 +++++++++--
ui/spice-display.c | 75 ++++++++++++++++++++++++++++----------
4 files changed, 81 insertions(+), 23 deletions(-)
diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h
index e271e011da..df74f5ee9b 100644
--- a/include/ui/spice-display.h
+++ b/include/ui/spice-display.h
@@ -153,6 +153,7 @@ struct SimpleSpiceCursor {
};
extern bool spice_opengl;
+extern bool spice_dmabuf_encode;
int qemu_spice_rect_is_empty(const QXLRect* r);
void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r);
diff --git a/qemu-options.hx b/qemu-options.hx
index aab8df0922..3016f8a6f7 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2143,7 +2143,7 @@ DEF("spice", HAS_ARG, QEMU_OPTION_spice,
" [,disable-agent-file-xfer=on|off][,agent-mouse=[on|off]]\n"
" [,playback-compression=[on|off]][,seamless-migration=[on|off]]\n"
" [,preferred-codec=<encoder>:<codec>\n"
- " [,gl=[on|off]][,rendernode=<file>]\n"
+ " [,gl=[on|off]][,rendernode=<file>][,dmabuf-encode=[on|off]]\n"
" enable spice\n"
" at least one of {port, tls-port} is mandatory\n",
QEMU_ARCH_ALL)
@@ -2248,6 +2248,10 @@ SRST
``rendernode=<file>``
DRM render node for OpenGL rendering. If not specified, it will
pick the first available. (Since 2.9)
+
+ ``dmabuf-encode=[on|off]``
+ Forward the dmabuf directly to the encoder (Gstreamer).
+ Default is off.
ERST
DEF("portrait", 0, QEMU_OPTION_portrait,
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 6e00211e3a..c9b856b056 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -494,6 +494,9 @@ static QemuOptsList qemu_spice_opts = {
},{
.name = "rendernode",
.type = QEMU_OPT_STRING,
+ },{
+ .name = "dmabuf-encode",
+ .type = QEMU_OPT_BOOL,
#endif
},
{ /* end of list */ }
@@ -843,11 +846,24 @@ static void qemu_spice_init(void)
g_free(password);
#ifdef HAVE_SPICE_GL
+ if (qemu_opt_get_bool(opts, "dmabuf-encode", 0)) {
+ spice_dmabuf_encode = 1;
+ }
if (qemu_opt_get_bool(opts, "gl", 0)) {
- if ((port != 0) || (tls_port != 0)) {
- error_report("SPICE GL support is local-only for now and "
- "incompatible with -spice port/tls-port");
+ if (((port != 0) || (tls_port != 0)) && !spice_dmabuf_encode) {
+ error_report("Add dmabuf-encode=on option to enable GL streaming");
exit(1);
+ } else if (spice_dmabuf_encode) {
+ if (port == 0 && tls_port == 0) {
+ error_report("dmabuf-encode=on is only meant to be used for "
+ "non-local displays");
+ exit(1);
+ }
+ if (g_strcmp0(preferred_codec, "gstreamer:h264")) {
+ error_report("dmabuf-encode=on currently only works and tested"
+ "with gstreamer:h264");
+ exit(1);
+ }
}
if (egl_rendernode_init(qemu_opt_get(opts, "rendernode"),
DISPLAYGL_MODE_ON) != 0) {
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 494168e7fe..90ada643a2 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -28,6 +28,7 @@
#include "ui/spice-display.h"
bool spice_opengl;
+bool spice_dmabuf_encode;
int qemu_spice_rect_is_empty(const QXLRect* r)
{
@@ -117,7 +118,7 @@ void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
}
static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd,
- QXLRect *rect)
+ QXLRect *rect, bool dmabuf)
{
SimpleSpiceUpdate *update;
QXLDrawable *drawable;
@@ -168,15 +169,17 @@ static void
qemu_spice_create_one_update(SimpleSpiceDisplay *ssd,
image->bitmap.palette = 0;
image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
- dest = pixman_image_create_bits(PIXMAN_LE_x8r8g8b8, bw, bh,
- (void *)update->bitmap, bw * 4);
- pixman_image_composite(PIXMAN_OP_SRC, ssd->surface, NULL, ssd->mirror,
- rect->left, rect->top, 0, 0,
- rect->left, rect->top, bw, bh);
- pixman_image_composite(PIXMAN_OP_SRC, ssd->mirror, NULL, dest,
- rect->left, rect->top, 0, 0,
- 0, 0, bw, bh);
- pixman_image_unref(dest);
+ if (!dmabuf) {
+ dest = pixman_image_create_bits(PIXMAN_LE_x8r8g8b8, bw, bh,
+ (void *)update->bitmap, bw * 4);
+ pixman_image_composite(PIXMAN_OP_SRC, ssd->surface, NULL, ssd->mirror,
+ rect->left, rect->top, 0, 0,
+ rect->left, rect->top, bw, bh);
+ pixman_image_composite(PIXMAN_OP_SRC, ssd->mirror, NULL, dest,
+ rect->left, rect->top, 0, 0,
+ 0, 0, bw, bh);
+ pixman_image_unref(dest);
+ }
cmd->type = QXL_CMD_DRAW;
cmd->data = (uintptr_t)drawable;
@@ -220,7 +223,7 @@ static void qemu_spice_create_update(SimpleSpiceDisplay
*ssd)
.left = x,
.right = x + bw,
};
- qemu_spice_create_one_update(ssd, &update);
+ qemu_spice_create_one_update(ssd, &update, false);
dirty_top[blk] = -1;
}
} else {
@@ -241,7 +244,7 @@ static void qemu_spice_create_update(SimpleSpiceDisplay
*ssd)
.left = x,
.right = x + bw,
};
- qemu_spice_create_one_update(ssd, &update);
+ qemu_spice_create_one_update(ssd, &update, false);
dirty_top[blk] = -1;
}
}
@@ -848,9 +851,26 @@ static void qemu_spice_gl_block_timer(void *opaque)
warn_report("spice: no gl-draw-done within one second");
}
+static void spice_gl_create_update(SimpleSpiceDisplay *ssd,
+ uint32_t width, uint32_t height)
+{
+ QXLRect update = {
+ .top = 0,
+ .bottom = height,
+ .left = 0,
+ .right = width,
+ };
+
+ WITH_QEMU_LOCK_GUARD(&ssd->lock) {
+ qemu_spice_create_one_update(ssd, &update, true);
+ }
+ qemu_spice_wakeup(ssd);
+}
+
static void spice_gl_refresh(DisplayChangeListener *dcl)
{
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+ bool local_display = spice_dmabuf_encode ? false : true;
uint64_t cookie;
if (!ssd->ds || qemu_console_is_gl_blocked(ssd->dcl.con)) {
@@ -865,7 +885,11 @@ static void spice_gl_refresh(DisplayChangeListener *dcl)
spice_qxl_gl_draw_async(&ssd->qxl, 0, 0,
surface_width(ssd->ds),
surface_height(ssd->ds),
- cookie);
+ cookie, local_display);
+ if (!local_display) {
+ spice_gl_create_update(ssd, surface_width(ssd->ds),
+ surface_height(ssd->ds));
+ }
ssd->gl_updates = 0;
}
}
@@ -891,6 +915,9 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
}
ssd->ds = new_surface;
if (ssd->ds) {
+ if (spice_dmabuf_encode) {
+ qemu_spice_create_host_primary(ssd);
+ }
surface_gl_create_texture(ssd->gls, ssd->ds);
fd = egl_get_fd_for_texture(ssd->ds->texture,
&stride, &fourcc,
@@ -909,7 +936,9 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
spice_qxl_gl_scanout(&ssd->qxl, fd,
surface_width(ssd->ds),
surface_height(ssd->ds),
- stride, fourcc, false);
+ stride, fourcc, false,
+ spice_dmabuf_encode ? false : true);
+
ssd->have_surface = true;
ssd->have_scanout = false;
@@ -932,7 +961,8 @@ static void
qemu_spice_gl_scanout_disable(DisplayChangeListener *dcl)
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
trace_qemu_spice_gl_scanout_disable(ssd->qxl.id);
- spice_qxl_gl_scanout(&ssd->qxl, -1, 0, 0, 0, 0, false);
+ spice_qxl_gl_scanout(&ssd->qxl, -1, 0, 0, 0, 0, false,
+ spice_dmabuf_encode ? false : true);
qemu_spice_gl_monitor_config(ssd, 0, 0, 0, 0);
ssd->have_surface = false;
ssd->have_scanout = false;
@@ -960,7 +990,9 @@ static void
qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
/* note: spice server will close the fd */
spice_qxl_gl_scanout(&ssd->qxl, fd, backing_width, backing_height,
- stride, fourcc, y_0_top);
+ stride, fourcc, y_0_top,
+ spice_dmabuf_encode ? false : true);
+
qemu_spice_gl_monitor_config(ssd, x, y, w, h);
ssd->have_surface = false;
ssd->have_scanout = true;
@@ -1031,6 +1063,7 @@ static void qemu_spice_gl_update(DisplayChangeListener
*dcl,
EGLint stride = 0, fourcc = 0;
bool render_cursor = false;
bool y_0_top = false; /* FIXME */
+ bool local_display = spice_dmabuf_encode ? false : true;
uint64_t cookie;
int fd;
@@ -1072,7 +1105,7 @@ static void qemu_spice_gl_update(DisplayChangeListener
*dcl,
&stride, &fourcc, NULL);
spice_qxl_gl_scanout(&ssd->qxl, fd,
dmabuf->width, dmabuf->height,
- stride, fourcc, false);
+ stride, fourcc, false, local_display);
}
} else {
trace_qemu_spice_gl_forward_dmabuf(ssd->qxl.id,
@@ -1081,7 +1114,7 @@ static void qemu_spice_gl_update(DisplayChangeListener
*dcl,
spice_qxl_gl_scanout(&ssd->qxl, dup(dmabuf->fd),
dmabuf->width, dmabuf->height,
dmabuf->stride, dmabuf->fourcc,
- dmabuf->y0_top);
+ dmabuf->y0_top, local_display);
}
qemu_spice_gl_monitor_config(ssd, 0, 0, dmabuf->width, dmabuf->height);
ssd->guest_dmabuf_refresh = false;
@@ -1104,7 +1137,11 @@ static void qemu_spice_gl_update(DisplayChangeListener
*dcl,
qemu_spice_gl_block(ssd, true);
glFlush();
cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0);
- spice_qxl_gl_draw_async(&ssd->qxl, x, y, w, h, cookie);
+ spice_qxl_gl_draw_async(&ssd->qxl, x, y, w, h, cookie, local_display);
+ if (!local_display) {
+ spice_gl_create_update(ssd, surface_width(ssd->ds),
+ surface_height(ssd->ds));
+ }
}
static const DisplayChangeListenerOps display_listener_gl_ops = {
--
2.37.2
- [RFC v2 0/2] spice: Add an option to forward the dmabuf directly to the encoder (v2), Vivek Kasireddy, 2023/01/23
- [RFC v2 1/2] spice: Add an option for users to provide a preferred codec, Vivek Kasireddy, 2023/01/23
- [RFC v2 2/2] spice: Add an option to forward the dmabuf directly to the encoder (v2),
Vivek Kasireddy <=
- Re: [RFC v2 2/2] spice: Add an option to forward the dmabuf directly to the encoder (v2), Gerd Hoffmann, 2023/01/23
- RE: [RFC v2 2/2] spice: Add an option to forward the dmabuf directly to the encoder (v2), Kasireddy, Vivek, 2023/01/24
- Re: [RFC v2 2/2] spice: Add an option to forward the dmabuf directly to the encoder (v2), Gerd Hoffmann, 2023/01/24
- Re: [RFC v2 2/2] spice: Add an option to forward the dmabuf directly to the encoder (v2), Frediano Ziglio, 2023/01/25
- RE: [RFC v2 2/2] spice: Add an option to forward the dmabuf directly to the encoder (v2), Kasireddy, Vivek, 2023/01/29