From cf678836a9632adca9ceb8a02de4c85740488c1a Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Sat, 22 Mar 2025 09:49:48 +0800 Subject: [PATCH] red-qxl: use RedGLScanout for multi plane support Create a new scanout struct supporting multi plane. We'll use this struct to create different protocol message for clients with different capability. Signed-off-by: Qiang Yu Acked-by: Frediano Ziglio --- server/dcc-send.cpp | 32 ++++++++++++++++++++++++++------ server/red-qxl.cpp | 40 +++++++++++++++++++++++++++------------- server/red-qxl.h | 16 ++++++++++++++-- server/video-stream.cpp | 8 ++++---- 4 files changed, 71 insertions(+), 25 deletions(-) diff --git a/server/dcc-send.cpp b/server/dcc-send.cpp index 1b34e6db..6c320232 100644 --- a/server/dcc-send.cpp +++ b/server/dcc-send.cpp @@ -1788,15 +1788,23 @@ static void red_marshall_gl_draw_stream(DisplayChannelClient *dcc, } QXLInstance* qxl = display->priv->qxl; - SpiceMsgDisplayGlScanoutUnix *scanout = red_qxl_get_gl_scanout(qxl); + RedGLScanout *scanout = red_qxl_get_gl_scanout(qxl); if (!scanout) { spice_warning("Cannot access scanout"); delete dmabuf_data; return; } - dmabuf_data->drm_dma_buf_fd = scanout->drm_dma_buf_fd; - dmabuf_data->drm_fourcc_format = scanout->drm_fourcc_format; + /* TODO: add support for it */ + if (scanout->num_planes > 1) { + spice_warning("Video encoder Does not support multi plane"); + red_qxl_put_gl_scanout(qxl, scanout); + delete dmabuf_data; + return; + } + + dmabuf_data->drm_dma_buf_fd = scanout->fd[0]; + dmabuf_data->drm_fourcc_format = scanout->fourcc; dmabuf_data->width = stream->width; dmabuf_data->height = stream->height; dmabuf_data->stride = stream->stride; @@ -2370,10 +2378,22 @@ static void marshall_gl_scanout(DisplayChannelClient *dcc, DisplayChannel *display_channel = DCC_TO_DC(dcc); QXLInstance* qxl = display_channel->priv->qxl; - SpiceMsgDisplayGlScanoutUnix *scanout = red_qxl_get_gl_scanout(qxl); + RedGLScanout *scanout = red_qxl_get_gl_scanout(qxl); if (scanout != nullptr) { - dcc->init_send_data(SPICE_MSG_DISPLAY_GL_SCANOUT_UNIX); - spice_marshall_msg_display_gl_scanout_unix(m, scanout); + if (scanout->num_planes <= 1) { + SpiceMsgDisplayGlScanoutUnix msg; + msg.drm_dma_buf_fd = scanout->fd[0]; + msg.width = scanout->width; + msg.height = scanout->height; + msg.stride = scanout->stride[0]; + msg.drm_fourcc_format = scanout->fourcc; + msg.flags = scanout->flags; + + dcc->init_send_data(SPICE_MSG_DISPLAY_GL_SCANOUT_UNIX); + spice_marshall_msg_display_gl_scanout_unix(m, &msg); + } else { + spice_error("gl scanout does not support multi plane"); + } } red_qxl_put_gl_scanout(qxl, scanout); } diff --git a/server/red-qxl.cpp b/server/red-qxl.cpp index 2979ae61..50db4f90 100644 --- a/server/red-qxl.cpp +++ b/server/red-qxl.cpp @@ -39,6 +39,13 @@ #include "red-qxl.h" +#ifdef HAVE_DRM_DRM_FOURCC_H +#include +#endif + +#ifndef DRM_FORMAT_MOD_INVALID +#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1) +#endif #define MAX_MONITORS_COUNT 16 @@ -61,7 +68,7 @@ struct QXLState { bool running; pthread_mutex_t scanout_mutex; - SpiceMsgDisplayGlScanoutUnix scanout; + RedGLScanout scanout; uint64_t gl_draw_cookie; template @@ -409,17 +416,17 @@ void spice_qxl_set_max_monitors(QXLInstance *instance, unsigned int max_monitors instance->st->max_monitors = MAX(1U, max_monitors); } -SpiceMsgDisplayGlScanoutUnix *red_qxl_get_gl_scanout(QXLInstance *qxl) +RedGLScanout *red_qxl_get_gl_scanout(QXLInstance *qxl) { pthread_mutex_lock(&qxl->st->scanout_mutex); - if (qxl->st->scanout.drm_dma_buf_fd >= 0) { + if (qxl->st->scanout.fd[0] >= 0) { return &qxl->st->scanout; } pthread_mutex_unlock(&qxl->st->scanout_mutex); return nullptr; } -void red_qxl_put_gl_scanout(QXLInstance *qxl, SpiceMsgDisplayGlScanoutUnix *scanout) +void red_qxl_put_gl_scanout(QXLInstance *qxl, RedGLScanout *scanout) { if (scanout) { pthread_mutex_unlock(&qxl->st->scanout_mutex); @@ -440,17 +447,22 @@ void spice_qxl_gl_scanout(QXLInstance *qxl, pthread_mutex_lock(&qxl_state->scanout_mutex); - if (qxl_state->scanout.drm_dma_buf_fd >= 0) { - close(qxl_state->scanout.drm_dma_buf_fd); + RedGLScanout *scanout = &qxl_state->scanout; + for (int i = 0; i < scanout->num_planes; i++) { + if (scanout->fd[i] >= 0) { + close(scanout->fd[i]); + } } - qxl_state->scanout = (SpiceMsgDisplayGlScanoutUnix) { - .drm_dma_buf_fd = fd, + qxl_state->scanout = (RedGLScanout) { + .fd = {fd, -1, -1, -1}, .width = width, .height = height, - .stride = stride, - .drm_fourcc_format = format, + .stride = {stride, 0, 0, 0}, + .fourcc = format, + .num_planes = 1, .flags = y_0_top ? SPICE_GL_SCANOUT_FLAGS_Y0TOP : 0, + .modifier = DRM_FORMAT_MOD_INVALID, }; pthread_mutex_unlock(&qxl_state->scanout_mutex); @@ -478,7 +490,7 @@ void spice_qxl_gl_draw_async(QXLInstance *qxl, spice_return_if_fail(qxl != nullptr); qxl_state = qxl->st; - if (qxl_state->scanout.drm_dma_buf_fd < 0) { + if (qxl_state->scanout.fd[0] < 0) { spice_warning("called spice_qxl_gl_draw_async without a buffer"); red_qxl_async_complete(qxl, cookie); return; @@ -576,9 +588,11 @@ void red_qxl_init(RedsState *reds, QXLInstance *qxl) qxl_state->reds = reds; qxl_state->qxl = qxl; pthread_mutex_init(&qxl_state->scanout_mutex, nullptr); - qxl_state->scanout.drm_dma_buf_fd = -1; qxl_state->gl_draw_cookie = GL_DRAW_COOKIE_INVALID; qxl_state->dispatcher = red::make_shared(RED_WORKER_MESSAGE_COUNT); + for (auto& fd : qxl_state->scanout.fd) { + fd = -1; + } qxl_state->max_monitors = UINT_MAX; qxl->st = qxl_state; @@ -619,7 +633,7 @@ void red_qxl_clear_pending(QXLState *qxl_state, int pending) bool red_qxl_get_allow_client_mouse(QXLInstance *qxl, int *x_res, int *y_res, int *allow_now) { // try to get resolution when 3D enabled, since qemu did not create QXL primary surface - SpiceMsgDisplayGlScanoutUnix *gl; + RedGLScanout *gl; if ((gl = red_qxl_get_gl_scanout(qxl))) { *x_res = gl->width; *y_res = gl->height; diff --git a/server/red-qxl.h b/server/red-qxl.h index 2084acb1..3dc40ca3 100644 --- a/server/red-qxl.h +++ b/server/red-qxl.h @@ -23,6 +23,18 @@ SPICE_BEGIN_DECLS +struct RedGLScanout { + int fd[4]; + uint32_t width; + uint32_t height; + uint32_t offset[4]; + uint32_t stride[4]; + uint32_t fourcc; + uint32_t num_planes; + uint32_t flags; + uint64_t modifier; +}; + void red_qxl_init(SpiceServer *reds, QXLInstance *qxl); void red_qxl_destroy(QXLInstance *qxl); @@ -37,8 +49,8 @@ void red_qxl_start(QXLInstance *qxl); uint32_t red_qxl_get_ram_size(QXLInstance *qxl); gboolean red_qxl_client_monitors_config(QXLInstance *qxl, VDAgentMonitorsConfig *monitors_config); bool red_qxl_get_allow_client_mouse(QXLInstance *qxl, int *x_res, int *y_res, int *allow_now); -SpiceMsgDisplayGlScanoutUnix *red_qxl_get_gl_scanout(QXLInstance *qxl); -void red_qxl_put_gl_scanout(QXLInstance *qxl, SpiceMsgDisplayGlScanoutUnix *scanout); +RedGLScanout *red_qxl_get_gl_scanout(QXLInstance *qxl); +void red_qxl_put_gl_scanout(QXLInstance *qxl, RedGLScanout *scanout); void red_qxl_gl_draw_async_complete(QXLInstance *qxl); int red_qxl_check_qxl_version(QXLInstance *qxl, int major, int minor); SpiceServer* red_qxl_get_server(QXLState *qxl); diff --git a/server/video-stream.cpp b/server/video-stream.cpp index 8418eed3..6048dd60 100644 --- a/server/video-stream.cpp +++ b/server/video-stream.cpp @@ -441,7 +441,7 @@ static void display_channel_create_stream(DisplayChannel *display, bool display_channel_create_gl_draw_stream(DisplayChannel *display) { QXLInstance* qxl = display->priv->qxl; - SpiceMsgDisplayGlScanoutUnix *scanout = red_qxl_get_gl_scanout(qxl); + RedGLScanout *scanout = red_qxl_get_gl_scanout(qxl); DisplayChannelClient *dcc; VideoStream *stream; bool ret = false; @@ -460,7 +460,7 @@ bool display_channel_create_gl_draw_stream(DisplayChannel *display) display_channel_surface_id_unref(display, 0); } if (!display_channel_create_surface(display, 0, scanout->width, - scanout->height, scanout->stride, + scanout->height, scanout->stride[0], SPICE_SURFACE_FMT_32_xRGB, nullptr, true, true)) { goto err; @@ -478,7 +478,7 @@ bool display_channel_create_gl_draw_stream(DisplayChannel *display) ret = true; display_channel_init_stream(display, stream, nullptr, &dest_area); stream->top_down = (scanout->flags & SPICE_GL_SCANOUT_FLAGS_Y0TOP) ? 0 : 1; - stream->stride = scanout->stride; + stream->stride = scanout->stride[0]; /* This is the upper bound; it should be possible to stream at 60 FPS * with a hardware based encoder. */ @@ -501,7 +501,7 @@ bool is_new_stream_needed(DisplayChannel *display) } QXLInstance* qxl = display->priv->qxl; - SpiceMsgDisplayGlScanoutUnix *scanout = red_qxl_get_gl_scanout(qxl); + RedGLScanout *scanout = red_qxl_get_gl_scanout(qxl); uint32_t width, height, top_down; if (!scanout) {