From 6c1a518539c17040c75af7eaa112c25377bece69 Mon Sep 17 00:00:00 2001 From: Michael Scherle Date: Tue, 13 May 2025 14:09:09 +0200 Subject: [PATCH] Send initial draw on client connect for DMA-BUF encoder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure an initial draw is sent immediately upon client connection if the DMA-BUF video encoder is in use. Without this, a frame would only be pushed when the screen content changes and the GPU renders a new frame—which could take a while, causing delays for the client. GStreamer now receives a duplicated file descriptor (fd) and takes responsibility for closing it. This guarantees the buffer remains available long enough. The previous fd mechanism is still retained to ensure a valid scanout buffer is always available for a new client. --- server/dcc-private.h | 1 + server/dcc-send.cpp | 16 +++++----------- server/dcc.cpp | 36 +++++++++++++++++++++++++++++------- server/dcc.h | 1 + server/gstreamer-encoder.c | 7 +++---- 5 files changed, 39 insertions(+), 22 deletions(-) diff --git a/server/dcc-private.h b/server/dcc-private.h index 0b42ee1e..28403063 100644 --- a/server/dcc-private.h +++ b/server/dcc-private.h @@ -66,6 +66,7 @@ struct DisplayChannelClientPrivate std::array stream_agents; uint64_t streams_max_bit_rate; bool gl_draw_ongoing; + bool gl_initial_draw_ongoing = FALSE; }; #include "pop-visibility.h" diff --git a/server/dcc-send.cpp b/server/dcc-send.cpp index aca79fd6..25108c11 100644 --- a/server/dcc-send.cpp +++ b/server/dcc-send.cpp @@ -20,6 +20,7 @@ #include #include +#include "dcc.h" #include "dcc-private.h" #include "display-channel-private.h" #include "red-qxl.h" @@ -1761,10 +1762,7 @@ static void red_free_cb(VideoEncoderDmabufData *video_dmabuf_data) { auto dmabuf_data = static_cast(video_dmabuf_data); auto dcc = dmabuf_data->dcc; - DisplayChannel *display = DCC_TO_DC(dcc); - - dcc->priv->gl_draw_ongoing = false; - display_channel_gl_draw_done(display); + dcc_handle_gl_draw_done(dcc); delete dmabuf_data; } @@ -1803,7 +1801,7 @@ static void red_marshall_gl_draw_stream(DisplayChannelClient *dcc, return; } - dmabuf_data->drm_dma_buf_fd = scanout->fd[0]; + dmabuf_data->drm_dma_buf_fd = dup(scanout->fd[0]); dmabuf_data->drm_fourcc_format = scanout->fourcc; dmabuf_data->width = stream->width; dmabuf_data->height = stream->height; @@ -1828,9 +1826,7 @@ static void red_marshall_gl_draw_stream(DisplayChannelClient *dcc, spice_warning("bad ret value (%d) from VideoEncoder::encode_dmabuf", ret); } - - dcc->priv->gl_draw_ongoing = false; - display_channel_gl_draw_done(display); + dcc_handle_gl_draw_done(dcc); delete dmabuf_data; return; } @@ -2432,9 +2428,7 @@ static void marshall_gl_draw(DisplayChannelClient *dcc, } else if (DCC_TO_DC(dcc)->priv->gl_draw_stream) { red_marshall_gl_draw_stream(dcc, m); } else if (dcc->priv->gl_draw_ongoing) { - auto display = DCC_TO_DC(dcc); - dcc->priv->gl_draw_ongoing = false; - display_channel_gl_draw_done(display); + dcc_handle_gl_draw_done(dcc); } else { spice_warning("nothing to send to the client"); } diff --git a/server/dcc.cpp b/server/dcc.cpp index 6e86a186..c89bcc5d 100644 --- a/server/dcc.cpp +++ b/server/dcc.cpp @@ -24,6 +24,7 @@ #include "red-client.h" #include "main-channel-client.h" #include +#include "red-qxl.h" #define DISPLAY_CLIENT_SHORT_TIMEOUT 15000000000ULL //nano #define DISPLAY_FREE_LIST_DEFAULT_SIZE 128 @@ -421,6 +422,22 @@ void dcc_start(DisplayChannelClient *dcc) dcc->pipe_add(dcc_gl_scanout_item_new(dcc, nullptr, 0)); dcc_push_monitors_config(dcc); } + + if (!dcc->is_gl_client()) { + QXLInstance* qxl = display->priv->qxl; + RedGLScanout *scanout = red_qxl_get_gl_scanout(qxl); + if (scanout) { + SpiceMsgDisplayGlDraw draw = { + .x = 0, + .y = 0, + .w = scanout->width, + .h = scanout->height + }; + red_qxl_put_gl_scanout(qxl, scanout); + dcc->pipe_add(dcc_gl_draw_item_new(dcc, &draw, -1)); + dcc_push_monitors_config(dcc); + } + } } static void dcc_destroy_stream_agents(DisplayChannelClient *dcc) @@ -531,7 +548,11 @@ RedPipeItemPtr dcc_gl_draw_item_new(RedChannelClient *rcc, void *data, int num) } } - dcc->priv->gl_draw_ongoing = TRUE; + if (num >= 0) { + dcc->priv->gl_draw_ongoing = TRUE; + } else { + dcc->priv->gl_initial_draw_ongoing = TRUE; + } auto item = red::make_shared(); item->draw = *draw; @@ -983,19 +1004,20 @@ GArray *dcc_get_preferred_video_codecs_for_encoding(DisplayChannelClient *dcc) return display_channel_get_video_codecs(DCC_TO_DC(dcc)); } -static bool dcc_handle_gl_draw_done(DisplayChannelClient *dcc) +bool dcc_handle_gl_draw_done(DisplayChannelClient *dcc) { DisplayChannel *display = DCC_TO_DC(dcc); - if (G_UNLIKELY(!dcc->priv->gl_draw_ongoing)) { + if (G_UNLIKELY(!dcc->priv->gl_initial_draw_ongoing && !dcc->priv->gl_draw_ongoing)) { g_warning("unexpected DRAW_DONE received\n"); /* close client connection */ return FALSE; } - - dcc->priv->gl_draw_ongoing = FALSE; - display_channel_gl_draw_done(display); - + if (!dcc->priv->gl_initial_draw_ongoing) { + dcc->priv->gl_draw_ongoing = FALSE; + display_channel_gl_draw_done(display); + } + dcc->priv->gl_initial_draw_ongoing = FALSE; return TRUE; } diff --git a/server/dcc.h b/server/dcc.h index c5aa09b2..6a388c8d 100644 --- a/server/dcc.h +++ b/server/dcc.h @@ -144,6 +144,7 @@ int dcc_compress_image (DisplayCha SpiceImage *dest, SpiceBitmap *src, Drawable *drawable, int can_lossy, compress_send_data_t* o_comp_data); +bool dcc_handle_gl_draw_done (DisplayChannelClient *dcc); void dcc_create_surface(DisplayChannelClient *dcc, struct RedSurface *surface); void dcc_push_surface_image(DisplayChannelClient *dcc, struct RedSurface *surface); diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index 448fed63..0957a2b2 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -1793,10 +1793,9 @@ spice_gst_encoder_encode_dmabuf(VideoEncoder *video_encoder, *outbuf = NULL; rc = VIDEO_ENCODER_FRAME_UNSUPPORTED; - mem = gst_dmabuf_allocator_alloc_with_flags(encoder->allocator, - dmabuf_data->drm_dma_buf_fd, - size, - GST_FD_MEMORY_FLAG_DONT_CLOSE); + mem = gst_dmabuf_allocator_alloc(encoder->allocator, + dmabuf_data->drm_dma_buf_fd, + size); if (!mem) { return rc; }