Skip to content

Commit

Permalink
fix: split WOLF_RENDER_NODE and WOLF_ENCODER_NODE, tests, docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ABeltramo committed Aug 22, 2024
1 parent a6b6490 commit 50d8e1d
Show file tree
Hide file tree
Showing 9 changed files with 472 additions and 58 deletions.
84 changes: 52 additions & 32 deletions docs/modules/user/pages/configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ Wolf is configured via a TOML config file and some additional optional ENV varia
|/dev/dri/renderD128
|The default render node used for virtual desktops; see: <<_multiple_gpu>>

|WOLF_ENCODER_NODE
|$WOLF_RENDER_NODE
|The default render node used for the Gstreamer pipelines; see: <<_multiple_gpu>>

|WOLF_DOCKER_FAKE_UDEV_PATH
|$HOST_APPS_STATE_FOLDER/fake-udev
|The path on the host for the fake-udev CLI tool
Expand Down Expand Up @@ -92,6 +96,12 @@ Can be changed in the `config.toml` file

=== Share home folder with multiple clients

[WARNING]
====
This will break isolation, if you want to connect with multiple clients at the same time you should not share the home folder.
You can follow development of that feature https://github.com/games-on-whales/wolf/issues/83[here]
====

By default, Wolf will create a new home folder for each client, but if you want to share the same home folder with multiple clients, you can set the `app_state_folder` to the same value for each paired client; example: +

[source,toml]
Expand Down Expand Up @@ -259,43 +269,19 @@ You can read more about gstreamer and custom pipelines in the xref:gstreamer.ado
When you have multiple GPUs installed in your host, you might want to have better control over which one is used by Wolf and how. +
There are two main separated parts that make use of HW acceleration in Wolf:

* Gstreamer video encoding: this will use HW acceleration in order to efficiently encode the video stream with H.264 or HEVC.
* App render node: this will use HW acceleration in order to create virtual Wayland desktops and run the chosen app (ex: Firefox, Steam, ...)
* *App render node*: this will use HW acceleration in order to create virtual Wayland desktops and run the chosen app (ex: Firefox, Steam, ...).
Use the `WOLF_RENDER_NODE` (defaults to `/dev/dri/renderD128`) env variable to control this.
* *Gstreamer video encoding*: this will use HW acceleration in order to efficiently encode the video stream with H.264 or HEVC.
Use the `WOLF_ENCODER_NODE` (defaults to `WOLF_RENDER_NODE`) env variable to control this.

They can be configured separately, and ideally you could even *use two GPUs at the same time* for different jobs; a common setup would be to use the integrated GPU just for the streaming part and use a powerful GPU to play apps/games.
They can be configured separately, and in theory you could even *use two GPUs at the same time* for different jobs; ex: use the integrated GPU just for the streaming part and use a powerful GPU to play apps/games.

=== Gstreamer video encoding

The streaming video encoding pipeline is fully controlled by the `config.toml` file; here the order in which entries are listed is important because Wolf will just try each listed plugin; the first one that works is the one that will be used.

[NOTE,caption=EXAMPLE]
[WARNING]
====
If you have an Intel iGPU and a Nvidia card in the same host, and you would like to use QuickSync in order to do the encoding, you can either:
* Delete the `nvcodec` entries under `gstreamer.video.hevc_encoders`
* Cut the `qsv` entry and paste it above the `nvcodec` entry
This isn't recommended, it might introduce additional latency and it's not optimal.
HW encoding on modern GPUs is very lightweight and it's better to use the same GPU for both jobs.
====

On top of that, each single `apps` entry support overriding the default streaming pipeline; for example:

[source,toml]
....
[[apps]]
title = "Test ball"
# More options here, removed for brevity...
[apps.video]
source = """
videotestsrc pattern=ball flip=true is-live=true !
video/x-raw, framerate={fps}/1
\
"""
....

In case you have two GPUs that will use the same encoder pipeline (example: an AMD iGPU and an AMD GPU card) you can override the `video_params` with the corresponding encoder plugin; see:
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1167[gstreamer/issues/1167].

=== App render node

Each application that Wolf will start will have access only to a specific render node even if the host has multiple GPUs connected. +
Expand Down Expand Up @@ -331,6 +317,40 @@ image = "ghcr.io/games-on-whales/steam:edge"
render_node = "/dev/dri/renderD129"
....

=== Gstreamer video encoding

The easy way to control this is to just edit the env variable `WOLF_ENCODER_NODE` (defaults to match `WOLF_RENDER_NODE` in order to use the same GPU for both), this will set the default render node used for the Gstreamer pipelines.

The streaming video encoding pipeline is fully controlled by the `config.toml` file; here the order in which entries are listed is important because Wolf will just try each listed plugin; the first one that works is the one that will be used.

[NOTE,caption=EXAMPLE]
====
If you have an Intel iGPU and a Nvidia card in the same host, and you would like to use QuickSync in order to do the encoding, you can either:
* Delete the `nvcodec` entries under `gstreamer.video.hevc_encoders`
* Cut the `qsv` entry and paste it above the `nvcodec` entry
====

On top of that, each single `apps` entry support overriding the default streaming pipeline; for example:

[source,toml]
....
[[apps]]
title = "Test ball"
# More options here, removed for brevity...
[apps.video]
source = """
videotestsrc pattern=ball flip=true is-live=true !
video/x-raw, framerate={fps}/1
\
"""
....

In case you have two GPUs that will use the same encoder pipeline (example: an AMD iGPU and an AMD GPU card) you can override the `video_params` with the corresponding encoder plugin; see:
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1167[gstreamer/issues/1167].

== Directly launch a Steam game

In order to directly launch a Steam game from Moonlight you can just copy the existing `[[apps]]` entry for Steam, change the name and just add the Steam app ID as env variable; example:
Expand Down
2 changes: 1 addition & 1 deletion src/moonlight-server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ function(make_includable input_file output_file)
endfunction(make_includable)

make_includable(rest/html/pin.html rest/html/pin.include.html)
make_includable(state/default/config.v2.toml state/default/config.include.toml)
make_includable(state/default/config.v4.toml state/default/config.include.toml)

# All users of this library will need at least C++17
target_compile_features(wolf_runner PUBLIC cxx_std_17)
Expand Down
17 changes: 8 additions & 9 deletions src/moonlight-server/state/configTOML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,9 @@ Config load_or_default(const std::string &source, const std::shared_ptr<dp::even
auto default_gst_audio_settings = toml::find<GstAudioCfg>(cfg, "gstreamer", "audio");
auto default_gst_encoder_settings = default_gst_video_settings.defaults;

std::string default_app_render_node =
utils::get_env("WOLF_RENDER_NODE", "/dev/dri/renderD128"); // TODO: WOLF_ENCODER_NODE
auto vendor = get_vendor(default_app_render_node);
auto default_app_render_node = utils::get_env("WOLF_RENDER_NODE", "/dev/dri/renderD128");
auto default_gst_render_node = utils::get_env("WOLF_ENCODER_NODE", default_app_render_node);
auto vendor = get_vendor(default_gst_render_node);

/* Automatic pick best encoders */
auto h264_encoder = get_encoder("H264", default_gst_video_settings.h264_encoders, vendor);
Expand Down Expand Up @@ -260,14 +260,13 @@ Config load_or_default(const std::string &source, const std::shared_ptr<dp::even
auto [idx, item] = pair;
auto app_title = toml::find<std::string>(item, "title");
auto app_render_node = toml::find_or(item, "render_node", default_app_render_node);
auto app_gpu_vendor = get_vendor(app_render_node);
if (app_gpu_vendor != vendor) {
if (app_render_node != default_gst_render_node) {
logs::log(logs::warning,
"App {} render node GPU vendor ({}) doesn't match the default GPU vendor ({})",
"App {} render node ({}) doesn't match the default GPU ({})",
app_title,
(int)app_gpu_vendor,
(int)vendor);
// TODO: allow user to override the default GPU vendor for the gstreamer pipeline
app_render_node,
default_gst_render_node);
// TODO: allow user to override gst_render_node
}

auto h264_gst_pipeline =
Expand Down
4 changes: 3 additions & 1 deletion src/moonlight-server/state/default/config.include.toml
Original file line number Diff line number Diff line change
Expand Up @@ -365,4 +365,6 @@ default_sink = """
rtpmoonlightpay_audio name=moonlight_pay packet_duration={packet_duration} encrypt={encrypt} \
aes_key="{aes_key}" aes_iv="{aes_iv}" !
udpsink bind-port={host_port} host={client_ip} port={client_port} sync=true\
""")for_c++_include"
"""

)for_c++_include"
Loading

0 comments on commit 50d8e1d

Please sign in to comment.