diff --git a/server/dcc.cpp b/server/dcc.cpp index c89bcc5d..6a993012 100644 --- a/server/dcc.cpp +++ b/server/dcc.cpp @@ -1004,6 +1004,11 @@ GArray *dcc_get_preferred_video_codecs_for_encoding(DisplayChannelClient *dcc) return display_channel_get_video_codecs(DCC_TO_DC(dcc)); } +const char * dcc_get_renderNode(DisplayChannelClient *dcc) +{ + return DCC_TO_DC(dcc)->priv->rendernode; +} + bool dcc_handle_gl_draw_done(DisplayChannelClient *dcc) { DisplayChannel *display = DCC_TO_DC(dcc); diff --git a/server/dcc.h b/server/dcc.h index 6a388c8d..716b4742 100644 --- a/server/dcc.h +++ b/server/dcc.h @@ -163,6 +163,7 @@ uint64_t dcc_get_max_stream_bit_rate(DisplayChannelClient *dcc); void dcc_set_max_stream_bit_rate(DisplayChannelClient *dcc, uint64_t rate); gboolean dcc_is_low_bandwidth(DisplayChannelClient *dcc); GArray *dcc_get_preferred_video_codecs_for_encoding(DisplayChannelClient *dcc); +const char * dcc_get_renderNode(DisplayChannelClient *dcc); void dcc_video_codecs_update(DisplayChannelClient *dcc); #include "pop-visibility.h" diff --git a/server/display-channel-private.h b/server/display-channel-private.h index e0693f54..e9e631be 100644 --- a/server/display-channel-private.h +++ b/server/display-channel-private.h @@ -106,6 +106,7 @@ struct DisplayChannelPrivate _Drawable *free_drawables; int stream_video; + const char *rendernode; GArray *video_codecs; uint32_t stream_count; std::array streams_buf; diff --git a/server/display-channel.cpp b/server/display-channel.cpp index c2a864c0..5fd68908 100644 --- a/server/display-channel.cpp +++ b/server/display-channel.cpp @@ -2163,13 +2163,14 @@ display_channel_new(RedsState *reds, QXLInstance *qxl, SpiceCoreInterfaceInternal *core, Dispatcher *dispatcher, int migrate, int stream_video, GArray *video_codecs, + const char* rendernode, uint32_t n_surfaces) { /* FIXME: migrate is not used...? */ spice_debug("create display channel"); auto display = red::make_shared(reds, qxl, core, dispatcher, migrate, stream_video, - video_codecs, n_surfaces); + video_codecs, rendernode, n_surfaces); if (display) { display_channel_set_stream_video(display.get(), stream_video); display->priv->gl_draw_stream = nullptr; @@ -2183,6 +2184,7 @@ DisplayChannel::DisplayChannel(RedsState *reds, Dispatcher *dispatcher, int migrate, int stream_video, GArray *video_codecs, + const char *rendernode, uint32_t n_surfaces): CommonGraphicsChannel(reds, SPICE_CHANNEL_DISPLAY, qxl->id, RedChannel::MigrateAll|RedChannel::HandleAcks, core, dispatcher) @@ -2238,6 +2240,7 @@ DisplayChannel::DisplayChannel(RedsState *reds, set_cap(SPICE_DISPLAY_CAP_CODEC_VP9_444); set_cap(SPICE_DISPLAY_CAP_CODEC_H265_444); // set_cap(SPICE_DISPLAY_CAP_CODEC_VP9_U); + priv->rendernode = rendernode; reds_register_channel(reds, this); } diff --git a/server/display-channel.h b/server/display-channel.h index c54df25c..3c17f725 100644 --- a/server/display-channel.h +++ b/server/display-channel.h @@ -47,6 +47,7 @@ struct DisplayChannel final: public CommonGraphicsChannel Dispatcher *dispatcher, int migrate, int stream_video, GArray *video_codecs, + const char *rendernode, uint32_t n_surfaces); ~DisplayChannel(); void on_connect(RedClient *client, RedStream *stream, int migration, @@ -93,6 +94,7 @@ display_channel_new(RedsState *reds, QXLInstance *qxl, SpiceCoreInterfaceInternal *core, Dispatcher *dispatcher, int migrate, int stream_video, GArray *video_codecs, + const char* rendernode, uint32_t n_surfaces); void display_channel_surface_id_unref(DisplayChannel *display, uint32_t surface_id); RedSurface *display_channel_create_surface(DisplayChannel *display, uint32_t surface_id, diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index c8e3fdea..5717cdc6 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -304,6 +304,7 @@ typedef struct SpiceGstEncoder { /* How many frames were dropped by the server since the last encoded frame. */ uint32_t server_drops; GstAllocator *allocator; + const char * rendernode; } SpiceGstEncoder; @@ -975,43 +976,38 @@ static bool gst_features_lookup(const gchar *feature_name) return true; } -static const gchar *get_encode_gpu(){ - const gchar* env_encode_gpu_str = g_getenv("SPICE_ENCODE_GPU"); - if ((!env_encode_gpu_str) || (strcmp(env_encode_gpu_str, "renderD128") == 0)) { - return NULL; - } - g_autoptr(GRegex) regex = g_regex_new("renderD1[[:digit:]]{2}", 0, 0, NULL); - if (g_regex_match(regex, env_encode_gpu_str, 0, NULL)) { - return env_encode_gpu_str; - } - return NULL; -} - -static gchar *find_best_hw_plugin(const gchar *codec_name) +static gchar *find_best_hw_plugin(const gchar *codec_name, const char *rendernode) { - char plugins[][20] = {"va","msdk", "vaapi"}; + char plugins[][8] = {"va","msdk", "vaapi"}; + char postproc[][10] ={"postproc","vpp","postproc"}; gchar *feature_name; int i; - const gchar *encode_gpu = get_encode_gpu(); - if (encode_gpu) { - g_strlcat(plugins[1], encode_gpu, sizeof(plugins[1])); - } - + for (i = 0; i < G_N_ELEMENTS(plugins); i++) { - feature_name = !codec_name ? g_strconcat(plugins[i], "postproc", NULL) : - g_strconcat(plugins[i], codec_name, "enc", NULL); - if (gst_features_lookup(feature_name)) { - return feature_name; - } - g_free(feature_name); - if(codec_name){ - feature_name = g_strconcat(plugins[i], codec_name, "lpenc", NULL); - if (gst_features_lookup(feature_name)) { - return feature_name; + if (codec_name == NULL){ + feature_name = g_strdup_printf("%s%s", plugins[i], postproc[i]); + if (!gst_features_lookup(feature_name)) { + g_free(feature_name); + continue; } + } else { + feature_name = g_strconcat(plugins[i], codec_name, "enc", NULL); + if (!gst_features_lookup(feature_name)) { + g_free(feature_name); + feature_name = g_strconcat(plugins[i], codec_name, "lpenc", NULL); + if (!gst_features_lookup(feature_name)) { + g_free(feature_name); + continue; + } + } + } + + if(i == 0 && rendernode){ + gchar * feature_name_with_render = g_strdup_printf("%s device-path=%s",feature_name, rendernode); g_free(feature_name); + return feature_name_with_render; } } return NULL; @@ -1058,11 +1054,11 @@ static void try_intel_hw_plugins(SpiceGstEncoder* spice_encoder, gchar **convert return; } - encoder = find_best_hw_plugin(codec_name); + encoder = find_best_hw_plugin(codec_name, spice_encoder->rendernode); if (!encoder) { return; } - vpp = find_best_hw_plugin(NULL); + vpp = find_best_hw_plugin(NULL,spice_encoder->rendernode); if (!vpp) { g_free(encoder); return; @@ -2077,7 +2073,8 @@ VideoEncoder *gstreamer_encoder_new(SpiceVideoCodecType codec_type, uint64_t starting_bit_rate, VideoEncoderRateControlCbs *cbs, bitmap_ref_t bitmap_ref, - bitmap_unref_t bitmap_unref) + bitmap_unref_t bitmap_unref, + const char * rendernode) { SPICE_VERIFY(SPICE_GST_FRAME_STATISTICS_COUNT <= SPICE_GST_HISTORY_SIZE); spice_return_val_if_fail(codec_type == SPICE_VIDEO_CODEC_TYPE_MJPEG || @@ -2122,6 +2119,7 @@ VideoEncoder *gstreamer_encoder_new(SpiceVideoCodecType codec_type, encoder->bitmap_ref = bitmap_ref; encoder->bitmap_unref = bitmap_unref; encoder->format = GSTREAMER_FORMAT_INVALID; + encoder->rendernode = rendernode; pthread_mutex_init(&encoder->outbuf_mutex, NULL); pthread_cond_init(&encoder->outbuf_cond, NULL); diff --git a/server/mjpeg-encoder.c b/server/mjpeg-encoder.c index 0110bba7..22200f4d 100644 --- a/server/mjpeg-encoder.c +++ b/server/mjpeg-encoder.c @@ -1364,7 +1364,8 @@ VideoEncoder *mjpeg_encoder_new(SpiceVideoCodecType codec_type, uint64_t starting_bit_rate, VideoEncoderRateControlCbs *cbs, bitmap_ref_t bitmap_ref, - bitmap_unref_t bitmap_unref) + bitmap_unref_t bitmap_unref, + const char *rendernode) { MJpegEncoder *encoder; diff --git a/server/red-worker.cpp b/server/red-worker.cpp index 76589da2..a60644b6 100644 --- a/server/red-worker.cpp +++ b/server/red-worker.cpp @@ -990,7 +990,9 @@ RedWorker* red_worker_new(QXLInstance *qxl) FALSE, reds_get_streaming_video(reds), reds_get_video_codecs(reds), - init_info.n_surfaces).get(); // XXX + reds_get_rendernode(reds), + init_info.n_surfaces + ).get(); // XXX channel = worker->display_channel; channel->init_stat_node(&worker->stat, "display_channel"); display_channel_set_image_compression(worker->display_channel, diff --git a/server/reds.cpp b/server/reds.cpp index 2cdf9250..28c5bf4c 100644 --- a/server/reds.cpp +++ b/server/reds.cpp @@ -121,6 +121,7 @@ struct RedServerConfig { char *sasl_appname; #endif char *spice_name; + char *rendernode; bool spice_uuid_is_set; uint8_t spice_uuid[16]; @@ -4093,6 +4094,16 @@ SPICE_GNUC_VISIBLE int spice_server_set_video_codecs(SpiceServer *reds, const ch return 0; } +SPICE_GNUC_VISIBLE int spice_server_set_rendernode(SpiceServer *s, const char *rendernode) { + g_free(s->config->rendernode); + s->config->rendernode = g_strdup(rendernode); + return 0; +} + +const char* reds_get_rendernode(const RedsState *reds){ + return reds->config->rendernode; +} + SPICE_GNUC_VISIBLE const char *spice_server_get_video_codecs(SpiceServer *reds) { return video_codecs_to_string(reds_get_video_codecs(reds), ";"); diff --git a/server/reds.h b/server/reds.h index 81b0fc1e..15d91da3 100644 --- a/server/reds.h +++ b/server/reds.h @@ -97,6 +97,7 @@ void reds_on_main_channel_migrate(RedsState *reds, MainChannelClient *mcc); uint32_t reds_get_streaming_video(const RedsState *reds); GArray* reds_get_video_codecs(const RedsState *reds); +const char* reds_get_rendernode(const RedsState *reds); spice_wan_compression_t reds_get_jpeg_state(const RedsState *reds); spice_wan_compression_t reds_get_zlib_glz_state(const RedsState *reds); SpiceCoreInterfaceInternal* reds_get_core_interface(RedsState *reds); diff --git a/server/spice-server.h b/server/spice-server.h index 739ac40a..5d967fe6 100644 --- a/server/spice-server.h +++ b/server/spice-server.h @@ -139,6 +139,8 @@ enum { int spice_server_set_video_codecs(SpiceServer *s, const char* video_codecs); +int spice_server_set_rendernode(SpiceServer *s, const char *rendernode); + /** * Returns a newly allocated string describing video encoders/codecs * currently allowed in @s Spice server. The string returned by diff --git a/server/spice-server.syms b/server/spice-server.syms index 8edb1619..ca60d80e 100644 --- a/server/spice-server.syms +++ b/server/spice-server.syms @@ -187,4 +187,5 @@ global: SPICE_SERVER_0.16 { global: spice_qxl_gl_scanout2; + spice_server_set_rendernode; } SPICE_SERVER_0.14.3; diff --git a/server/tests/test-display-base.cpp b/server/tests/test-display-base.cpp index b220b7fe..9b43441e 100644 --- a/server/tests/test-display-base.cpp +++ b/server/tests/test-display-base.cpp @@ -806,7 +806,7 @@ static QXLInterface display_sif = { .major_version = SPICE_INTERFACE_QXL_MAJOR, .minor_version = SPICE_INTERFACE_QXL_MINOR }, - { .attached_worker = attached_worker }, + .attached_worker = attached_worker , .set_compression_level = set_compression_level, .set_mm_time = nullptr, .get_init_info = get_init_info, diff --git a/server/tests/test-gst.cpp b/server/tests/test-gst.cpp index 19ad879b..6ed6327f 100644 --- a/server/tests/test-gst.cpp +++ b/server/tests/test-gst.cpp @@ -692,7 +692,7 @@ create_video_encoder(const EncoderInfo *encoder) spice_assert(encoder); video_encoder = encoder->new_encoder(encoder->coded_type, starting_bit_rate, &rate_control_cbs, - (bitmap_ref_t) frame_ref, (bitmap_unref_t) frame_unref); + (bitmap_ref_t) frame_ref, (bitmap_unref_t) frame_unref, NULL); if (video_encoder == NULL) { exit(123); } diff --git a/server/video-encoder.h b/server/video-encoder.h index 57d9b9b9..fc329f32 100644 --- a/server/video-encoder.h +++ b/server/video-encoder.h @@ -208,19 +208,22 @@ typedef VideoEncoder* (*new_video_encoder_t)(SpiceVideoCodecType codec_type, uint64_t starting_bit_rate, VideoEncoderRateControlCbs *cbs, bitmap_ref_t bitmap_ref, - bitmap_unref_t bitmap_unref); + bitmap_unref_t bitmap_unref, + const char * rendernode); VideoEncoder* mjpeg_encoder_new(SpiceVideoCodecType codec_type, uint64_t starting_bit_rate, VideoEncoderRateControlCbs *cbs, bitmap_ref_t bitmap_ref, - bitmap_unref_t bitmap_unref); + bitmap_unref_t bitmap_unref, + const char * rendernode); #if defined(HAVE_GSTREAMER_1_0) VideoEncoder* gstreamer_encoder_new(SpiceVideoCodecType codec_type, uint64_t starting_bit_rate, VideoEncoderRateControlCbs *cbs, bitmap_ref_t bitmap_ref, - bitmap_unref_t bitmap_unref); + bitmap_unref_t bitmap_unref, + const char * rendernode); #endif diff --git a/server/video-stream.cpp b/server/video-stream.cpp index 798b7206..7830f9bc 100644 --- a/server/video-stream.cpp +++ b/server/video-stream.cpp @@ -820,7 +820,7 @@ static VideoEncoder* dcc_create_video_encoder(DisplayChannelClient *dcc, continue; } - VideoEncoder* video_encoder = video_codec->create(video_codec->type, starting_bit_rate, cbs, bitmap_ref, bitmap_unref); + VideoEncoder* video_encoder = video_codec->create(video_codec->type, starting_bit_rate, cbs, bitmap_ref, bitmap_unref, dcc_get_renderNode(dcc)); if (video_encoder) { return video_encoder; } @@ -828,7 +828,7 @@ static VideoEncoder* dcc_create_video_encoder(DisplayChannelClient *dcc, /* Try to use the builtin MJPEG video encoder as a fallback */ if (!client_has_multi_codec || dcc->test_remote_cap(SPICE_DISPLAY_CAP_CODEC_MJPEG)) { - return mjpeg_encoder_new(SPICE_VIDEO_CODEC_TYPE_MJPEG, starting_bit_rate, cbs, bitmap_ref, bitmap_unref); + return mjpeg_encoder_new(SPICE_VIDEO_CODEC_TYPE_MJPEG, starting_bit_rate, cbs, bitmap_ref, bitmap_unref, dcc_get_renderNode(dcc)); } return nullptr;