[Spice-devel] [PATCH v1 3/5] dcc-send: Encode and send gl_draw stream data to the remote client
Frediano Ziglio
freddy77 at gmail.com
Fri Apr 21 18:45:54 UTC 2023
Il giorno gio 16 mar 2023 alle ore 06:05 Vivek Kasireddy
<vivek.kasireddy at intel.com> ha scritto:
>
> For remote (or non-gl) clients, if a valid gl_draw stream exists,
> then we first extract the dmabuf fd associated with the scanout and
> share it with the encoder along with other key parameters such as
> stride, width and height. Once the encoder finishes creating an
> encoded buffer (using the dmabuf fd as input), we then send it
> over to the client. Also, as soon as the encoder notifies that
> it is no longer using the dmabuf fd, we send a gl_draw_done async
> to the application.
>
> Cc: Gerd Hoffmann <kraxel at redhat.com>
> Cc: Marc-André Lureau <marcandre.lureau at redhat.com>
> Cc: Dongwon Kim <dongwon.kim at intel.com>
> Signed-off-by: Vivek Kasireddy <vivek.kasireddy at intel.com>
> ---
> server/dcc-send.cpp | 89 +++++++++++++++++++++++++++++++++++++++++-
> server/video-encoder.h | 13 ++++++
> 2 files changed, 100 insertions(+), 2 deletions(-)
>
> diff --git a/server/dcc-send.cpp b/server/dcc-send.cpp
> index 2c40a231..94cbe7e7 100644
> --- a/server/dcc-send.cpp
> +++ b/server/dcc-send.cpp
> @@ -1730,6 +1730,82 @@ static bool red_marshall_stream_data(DisplayChannelClient *dcc,
> return TRUE;
> }
>
> +static void red_gst_mem_free_cb(void *opaque)
I won't use "gst" here, this is for a generic encoder.
> +{
> + auto dcc = static_cast<DisplayChannelClient *>(opaque);
> + DisplayChannel *display = DCC_TO_DC(dcc);
> +
> + dcc->priv->gl_draw_ongoing = FALSE;
minor, false
> + display_channel_gl_draw_done(display);
This looks like a free() which is not freeing the object, other
callbacks in SPICE free the object.
> +}
> +
> +static void red_marshall_gl_draw_stream(DisplayChannelClient *dcc,
> + SpiceMarshaller *base_marshaller)
> +{
> + DisplayChannel *display = DCC_TO_DC(dcc);
> + QXLInstance* qxl = display->priv->qxl;
> + VideoEncoderDmabufData *dmabuf_data = nullptr;
> +
> + VideoStream *stream = dcc->priv->gl_draw_stream;
> + SpiceMsgDisplayGlScanoutUnix *scanout = red_qxl_get_gl_scanout(qxl);
> + if (scanout != nullptr) {
"if (scanout)" suffice... not strong about.
> + dmabuf_data = g_new0(VideoEncoderDmabufData, 1);
Use new/delete instead?
> + dmabuf_data->drm_dma_buf_fd = scanout->drm_dma_buf_fd;
> + dmabuf_data->width = stream->width;
> + dmabuf_data->height = stream->height;
> + dmabuf_data->stride = scanout->stride;
> + dmabuf_data->opaque = dcc;
Why an opaque pointer? Better a proper typed pointer.
> + dmabuf_data->notify_mem_free = red_gst_mem_free_cb;
> + }
> + red_qxl_put_gl_scanout(qxl, scanout);
> + if (!dmabuf_data) {
> + spice_warning("scanout is not valid");
> + return;
> + }
> +
> + int stream_id = display_channel_get_video_stream_id(display, stream);
> + VideoStreamAgent *agent = &dcc->priv->stream_agents[stream_id];
> + uint32_t frame_mm_time = reds_get_mm_time();
> + VideoBuffer *outbuf;
> + VideoEncodeResults ret;
> +
> + ret = !agent->video_encoder || !agent->video_encoder->encode_dmabuf ?
> + VIDEO_ENCODER_FRAME_UNSUPPORTED :
> + agent->video_encoder->encode_dmabuf(agent->video_encoder,
> + frame_mm_time,
> + dmabuf_data, &outbuf);
> + switch (ret) {
> + case VIDEO_ENCODER_FRAME_ENCODE_DONE:
> + break;
> + case VIDEO_ENCODER_FRAME_DROP:
> +#ifdef STREAM_STATS
> + agent->stats.num_drops_fps++;
> +#endif
> + case VIDEO_ENCODER_FRAME_UNSUPPORTED:
> + default:
> + spice_warning("bad return value (%d) from VideoEncoder::encode_dmabuf", ret);
> + display_channel_gl_draw_done(display);
I don't know why but not setting dcc->priv->gl_draw_ongoing here smells bad.
> + g_free(dmabuf_data);
> + return;
> + }
> +
> + SpiceMsgDisplayStreamData stream_data;
> +
> + dcc->init_send_data(SPICE_MSG_DISPLAY_STREAM_DATA);
> + stream_data.base.id = stream_id;
> + stream_data.base.multi_media_time = frame_mm_time;
> + stream_data.data_size = outbuf->size;
> + spice_marshall_msg_display_stream_data(base_marshaller, &stream_data);
> +
> + spice_marshaller_add_by_ref_full(base_marshaller, outbuf->data, outbuf->size,
> + &red_release_video_encoder_buffer, outbuf);
> +#ifdef STREAM_STATS
> + agent->stats.num_frames_sent++;
> + agent->stats.size_sent += outbuf->size;
> + agent->stats.end = frame_mm_time;
> +#endif
> +}
> +
> static inline void marshall_inval_palette(RedChannelClient *rcc,
> SpiceMarshaller *base_marshaller,
> RedCachePipeItem *cache_item)
> @@ -2126,6 +2202,8 @@ static void marshall_stream_start(DisplayChannelClient *dcc,
> if (stream->current) {
> RedDrawable *red_drawable = stream->current->red_drawable.get();
> stream_create.clip = red_drawable->clip;
> + } else if (stream == dcc->priv->gl_draw_stream){
> + stream_create.clip.type = SPICE_CLIP_TYPE_NONE;
Is this necessary?
> } else {
> stream_create.clip.type = SPICE_CLIP_TYPE_RECTS;
> clip_rects.num_rects = 0;
> @@ -2279,10 +2357,17 @@ static void marshall_gl_draw(RedChannelClient *rcc,
> SpiceMarshaller *m,
> RedPipeItem *item)
> {
> + DisplayChannelClient *dcc = DISPLAY_CHANNEL_CLIENT(rcc);
See fixups branch
> auto p = static_cast<RedGlDrawItem*>(item);
>
> - rcc->init_send_data(SPICE_MSG_DISPLAY_GL_DRAW);
> - spice_marshall_msg_display_gl_draw(m, &p->draw);
> + if (dcc_is_gl_client(dcc)) {
> + rcc->init_send_data(SPICE_MSG_DISPLAY_GL_DRAW);
> + spice_marshall_msg_display_gl_draw(m, &p->draw);
> + } else if (dcc->priv->gl_draw_stream) {
> + red_marshall_gl_draw_stream(dcc, m);
> + } else {
> + spice_warning("nothing to send to the client");
> + }
> }
>
>
> diff --git a/server/video-encoder.h b/server/video-encoder.h
> index d5bc0a68..8eb71ca1 100644
> --- a/server/video-encoder.h
> +++ b/server/video-encoder.h
> @@ -56,6 +56,15 @@ typedef struct VideoEncoderStats {
> double avg_quality;
> } VideoEncoderStats;
>
> +typedef struct VideoEncoderDmabufData {
> + int32_t drm_dma_buf_fd;
See fixups branch
> + uint32_t width;
> + uint32_t height;
> + uint32_t stride;
> + void *opaque;
I would avoid the opaque and extend in dcc-send.
> + void (*notify_mem_free)(void *opaque);
Here I would use a "void (*free)(struct VideoEncoderDmabufData*)".
> +} VideoEncoderDmabufData;
> +
> typedef struct VideoEncoder VideoEncoder;
> struct VideoEncoder {
> /* Releases the video encoder's resources */
> @@ -84,6 +93,10 @@ struct VideoEncoder {
> const SpiceRect *src, int top_down,
> gpointer bitmap_opaque, VideoBuffer** outbuf);
>
> + VideoEncodeResults (*encode_dmabuf)(VideoEncoder *encoder, uint32_t frame_mm_time,
> + VideoEncoderDmabufData *dmabuf_data,
> + VideoBuffer** outbuf);
> +
> /*
> * Bit rate control methods.
> */
Frediano
More information about the Spice-devel
mailing list