Make '-w screen' capture the first monitor on nvidia x11 as well to make it work like amd, intel and nvidia wayland. Keep screen-direct for all monitors, that is gsync compatible

This commit is contained in:
dec05eba
2024-12-19 00:42:33 +01:00
parent a006261ade
commit c1048a3d20
5 changed files with 62 additions and 75 deletions

View File

@@ -23,9 +23,8 @@ Supported audio codecs:
## Note
This software works on X11 and Wayland on AMD, Intel and NVIDIA.
### TEMPORARY ISSUES
1) screen-direct capture has been temporary disabled as it causes issues with stuttering. This might be a nvfbc bug.
2) Videos are in variable framerate format. Use MPV to play such videos, otherwise you might experience stuttering in the video if you are using a buggy video player. You can try saving the video into a .mkv file instead as some software may have better support for .mkv files (such as kdenlive). You can use the "-fm cfr" option to to use constant framerate mode.
3) FLAC audio codec is disabled at the moment because of temporary issues.
1) Videos are in variable framerate format. Use MPV to play such videos, otherwise you might experience stuttering in the video if you are using a buggy video player. You can try saving the video into a .mkv file instead as some software may have better support for .mkv files (such as kdenlive). You can use the "-fm cfr" option to to use constant framerate mode.
2) FLAC audio codec is disabled at the moment because of temporary issues.
### AMD/Intel/Wayland root permission
When recording a window or when using the `-w portal` option under AMD/Intel no special user permission is required,
however when recording a monitor (or when using wayland) the program needs root permission (to access KMS).\
@@ -44,7 +43,7 @@ To enable overclocking for optimal performance use the `-oc` option when running
Note that this only works when Xorg server is running as root, and using this option will only give you a performance boost if the game you are recording is bottlenecked by your GPU.\
Note! use at your own risk!
# VRR/G-SYNC
This should work fine on AMD/Intel X11 or Wayland. On Nvidia X11 G-SYNC only works with the -w screen-direct-force option, but because of bugs in the Nvidia driver this option is not always recommended.
This should work fine on AMD/Intel X11 or Wayland. On Nvidia X11 G-SYNC only works with the -w screen-direct option, but because of bugs in the Nvidia driver this option is not always recommended.
For example it can cause your computer to freeze when recording certain games.
# Installation

11
TODO
View File

@@ -197,3 +197,14 @@ Improve software encoding performance.
Add option to record audio from the recorded window only.
Add option to automatically select best video codec available. Add -k best, -k best_10bit and -k best_hdr.
HDR is broken on kde plasma > 6.2 because of change to how HDR metadata works. See https://github.com/dec05eba/gpu-screen-recorder-issues/issues/60.
Use wayland color management protocol when it's available: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/14.
Use different exit codes for different errors. Use one for invalid -w option, another one for invalid -a option for audio devices, etc. This is to make UI error reporting better.
Document these exit codes in an exit code .md file, or finally create a manpage where this can be documented.
Ffmpeg fixed black bars in videos on amd when using hevc and when recording at some resolutions, such as 1080p:
https://github.com/FFmpeg/FFmpeg/commit/bcfbf2bac8f9eeeedc407b40596f5c7aaa0d5b47
https://github.com/FFmpeg/FFmpeg/commit/d0facac679faf45d3356dff2e2cb382580d7a521
Disable gpu screen recorder black bar handling when using hevc on amd when the libavcodec version is the one that comes after those commits.

View File

@@ -137,7 +137,7 @@ bool gsr_damage_set_target_monitor(gsr_damage *self, const char *monitor_name) {
}
memset(&self->monitor, 0, sizeof(self->monitor));
if(strcmp(monitor_name, "screen") != 0 && strcmp(monitor_name, "screen-direct") != 0 && strcmp(monitor_name, "screen-direct-force") != 0) {
if(strcmp(monitor_name, "screen-direct") != 0 && strcmp(monitor_name, "screen-direct-force") != 0) {
if(!get_monitor_by_name(self->egl, GSR_CONNECTION_X11, monitor_name, &self->monitor))
fprintf(stderr, "gsr warning: gsr_damage_set_target_monitor: failed to find monitor: %s\n", monitor_name);
}

View File

@@ -377,7 +377,7 @@ bool gsr_egl_load(gsr_egl *self, gsr_window *window, bool is_monitor_capture) {
self->glx_library = dlopen("libGLX.so.0", RTLD_LAZY);
self->gl_library = dlopen("libGL.so.1", RTLD_LAZY);
if(!self->egl_library) {
if(!self->gl_library) {
fprintf(stderr, "gsr error: gsr_egl_load: failed to load libGL.so.1, error: %s\n", dlerror());
goto fail;
}

View File

@@ -1080,15 +1080,14 @@ static void usage_full() {
usage_header();
printf("\n");
printf("OPTIONS:\n");
printf(" -w Window id to record, a display (monitor name), \"screen\", \"screen-direct-force\", \"focused\" or \"portal\".\n");
printf(" -w Window id to record, a display (monitor name), \"screen\", \"screen-direct\", \"focused\" or \"portal\".\n");
printf(" If this is \"portal\" then xdg desktop screencast portal with PipeWire will be used. Portal option is only available on Wayland.\n");
printf(" If you select to save the session (token) in the desktop portal capture popup then the session will be saved for the next time you use \"portal\",\n");
printf(" but the session will be ignored unless you run GPU Screen Recorder with the '-restore-portal-session yes' option.\n");
printf(" If this is \"screen\" or \"screen-direct-force\" then all monitors are recorded on Nvidia X11.\n");
printf(" On AMD/Intel or wayland \"screen\" will record the first monitor found.\n");
printf(" \"screen-direct-force\" is not recommended unless you use a VRR (G-SYNC) monitor on Nvidia X11 and you are aware that using this option can cause\n");
printf(" games to freeze/crash or other issues because of Nvidia driver issues.\n");
printf(" \"screen-direct-force\" option is only available on Nvidia X11. VRR works without this option on other systems.\n");
printf(" If this is \"screen\" then the first monitor found is recorded.\n");
printf(" \"screen-direct\" can only be used on Nvidia X11, to allow recording without breaking VRR (G-SYNC). This also records all of your monitors.\n");
printf(" Using this \"screen-direct\" option is not recommended unless you use VRR (G-SYNC) as there are Nvidia driver issues that can cause your system or games to freeze/crash.\n");
printf(" The \"screen-direct\" option is not needed on AMD, Intel nor Nvidia on Wayland as VRR works properly in those cases.\n");
printf(" Run GPU Screen Recorder with the --list-capture-options option to list valid values for this option.\n");
printf("\n");
printf(" -c Container format for output file, for example mp4, or flv. Only required if no output file is specified or if recording in replay buffer mode.\n");
@@ -2060,7 +2059,7 @@ static void output_monitor_info(const gsr_monitor *monitor, void *userdata) {
}
}
static void list_supported_capture_options(const gsr_window *window, const char *card_path, gsr_gpu_vendor vendor, bool list_monitors) {
static void list_supported_capture_options(const gsr_window *window, const char *card_path, bool list_monitors) {
const bool wayland = gsr_window_get_display_server(window) == GSR_DISPLAY_SERVER_WAYLAND;
if(!wayland) {
puts("window");
@@ -2070,14 +2069,9 @@ static void list_supported_capture_options(const gsr_window *window, const char
if(list_monitors) {
capture_options_callback options;
options.window = window;
if(monitor_capture_use_drm(window, vendor)) {
const bool is_x11 = gsr_window_get_display_server(window) == GSR_DISPLAY_SERVER_X11;
const gsr_connection_type connection_type = is_x11 ? GSR_CONNECTION_X11 : GSR_CONNECTION_DRM;
for_each_active_monitor_output(window, card_path, connection_type, output_monitor_info, &options);
} else {
puts("screen"); // All monitors in one, only available on Nvidia X11
for_each_active_monitor_output(window, card_path, GSR_CONNECTION_X11, output_monitor_info, &options);
}
const bool is_x11 = gsr_window_get_display_server(window) == GSR_DISPLAY_SERVER_X11;
const gsr_connection_type connection_type = is_x11 ? GSR_CONNECTION_X11 : GSR_CONNECTION_DRM;
for_each_active_monitor_output(window, card_path, connection_type, output_monitor_info, &options);
}
#ifdef GSR_PORTAL
@@ -2155,7 +2149,7 @@ static void info_command() {
puts("section=video_codecs");
list_supported_video_codecs(&egl, wayland);
puts("section=capture_options");
list_supported_capture_options(window, egl.card_path, egl.gpu_info.vendor, list_monitors);
list_supported_capture_options(window, egl.card_path, list_monitors);
fflush(stdout);
@@ -2207,6 +2201,7 @@ static void list_application_audio_command() {
// |card_path| can be NULL. If not NULL then |vendor| has to be valid
static void list_capture_options_command(const char *card_path, gsr_gpu_vendor vendor) {
(void)vendor;
bool wayland = false;
Display *dpy = XOpenDisplay(nullptr);
if (!dpy) {
@@ -2235,7 +2230,7 @@ static void list_capture_options_command(const char *card_path, gsr_gpu_vendor v
}
if(card_path) {
list_supported_capture_options(window, card_path, vendor, true);
list_supported_capture_options(window, card_path, true);
} else {
gsr_egl egl;
if(!gsr_egl_load(&egl, window, false)) {
@@ -2252,7 +2247,7 @@ static void list_capture_options_command(const char *card_path, gsr_gpu_vendor v
list_monitors = false;
}
}
list_supported_capture_options(window, egl.card_path, egl.gpu_info.vendor, list_monitors);
list_supported_capture_options(window, egl.card_path, list_monitors);
}
fflush(stdout);
@@ -2281,6 +2276,35 @@ static bool gpu_vendor_from_string(const char *vendor_str, gsr_gpu_vendor *vendo
}
}
static void validate_monitor_get_valid(const gsr_egl *egl, std::string &window_str) {
const bool is_x11 = gsr_window_get_display_server(egl->window) == GSR_DISPLAY_SERVER_X11;
const gsr_connection_type connection_type = is_x11 ? GSR_CONNECTION_X11 : GSR_CONNECTION_DRM;
const bool capture_use_drm = monitor_capture_use_drm(egl->window, egl->gpu_info.vendor);
if(strcmp(window_str.c_str(), "screen") == 0) {
FirstOutputCallback first_output;
first_output.output_name = NULL;
for_each_active_monitor_output(egl->window, egl->card_path, connection_type, get_first_output, &first_output);
if(first_output.output_name) {
window_str = first_output.output_name;
} else {
fprintf(stderr, "Error: no usable output found\n");
_exit(1);
}
} else if(capture_use_drm || (strcmp(window_str.c_str(), "screen-direct") != 0 && strcmp(window_str.c_str(), "screen-direct-force") != 0)) {
gsr_monitor gmon;
if(!get_monitor_by_name(egl, connection_type, window_str.c_str(), &gmon)) {
fprintf(stderr, "gsr error: display \"%s\" not found, expected one of:\n", window_str.c_str());
fprintf(stderr, " \"screen\"\n");
if(!capture_use_drm)
fprintf(stderr, " \"screen-direct\"\n");
for_each_active_monitor_output(egl->window, egl->card_path, connection_type, monitor_output_callback_print, NULL);
_exit(1);
}
}
}
static gsr_capture* create_capture_impl(std::string &window_str, vec2i output_resolution, bool wayland, gsr_egl *egl, int fps, VideoCodec video_codec, gsr_color_range color_range,
bool record_cursor, bool use_software_video_encoder, bool restore_portal_session, const char *portal_session_token_filepath,
gsr_color_depth color_depth)
@@ -2325,60 +2349,13 @@ static gsr_capture* create_capture_impl(std::string &window_str, vec2i output_re
_exit(2);
#endif
} else if(contains_non_hex_number(window_str.c_str())) {
if(monitor_capture_use_drm(egl->window, egl->gpu_info.vendor)) {
const bool is_x11 = gsr_window_get_display_server(egl->window) == GSR_DISPLAY_SERVER_X11;
const gsr_connection_type connection_type = is_x11 ? GSR_CONNECTION_X11 : GSR_CONNECTION_DRM;
if(strcmp(window_str.c_str(), "screen") == 0) {
FirstOutputCallback first_output;
first_output.output_name = NULL;
for_each_active_monitor_output(egl->window, egl->card_path, connection_type, get_first_output, &first_output);
if(first_output.output_name) {
window_str = first_output.output_name;
} else {
fprintf(stderr, "Error: no usable output found\n");
_exit(1);
}
} else {
gsr_monitor gmon;
if(!get_monitor_by_name(egl, connection_type, window_str.c_str(), &gmon)) {
fprintf(stderr, "gsr error: display \"%s\" not found, expected one of:\n", window_str.c_str());
fprintf(stderr, " \"screen\"\n");
for_each_active_monitor_output(egl->window, egl->card_path, connection_type, monitor_output_callback_print, NULL);
_exit(1);
}
}
} else {
if(strcmp(window_str.c_str(), "screen") != 0 && strcmp(window_str.c_str(), "screen-direct") != 0 && strcmp(window_str.c_str(), "screen-direct-force") != 0) {
gsr_monitor gmon;
if(!get_monitor_by_name(egl, GSR_CONNECTION_X11, window_str.c_str(), &gmon)) {
Display *display = (Display*)gsr_window_get_display(egl->window);
const int screens_width = XWidthOfScreen(DefaultScreenOfDisplay(display));
const int screens_height = XWidthOfScreen(DefaultScreenOfDisplay(display));
fprintf(stderr, "gsr error: display \"%s\" not found, expected one of:\n", window_str.c_str());
fprintf(stderr, " \"screen\" (%dx%d+%d+%d)\n", screens_width, screens_height, 0, 0);
fprintf(stderr, " \"screen-direct\" (%dx%d+%d+%d)\n", screens_width, screens_height, 0, 0);
fprintf(stderr, " \"screen-direct-force\" (%dx%d+%d+%d)\n", screens_width, screens_height, 0, 0);
for_each_active_monitor_output(egl->window, egl->card_path, GSR_CONNECTION_X11, monitor_output_callback_print, NULL);
_exit(1);
}
}
}
if(egl->gpu_info.vendor == GSR_GPU_VENDOR_NVIDIA && !wayland) {
validate_monitor_get_valid(egl, window_str);
if(!monitor_capture_use_drm(egl->window, egl->gpu_info.vendor)) {
const char *capture_target = window_str.c_str();
bool direct_capture = strcmp(window_str.c_str(), "screen-direct") == 0;
const bool direct_capture = strcmp(window_str.c_str(), "screen-direct") == 0 || strcmp(window_str.c_str(), "screen-direct-force") == 0;
if(direct_capture) {
capture_target = "screen";
// TODO: Temporary disable direct capture because push model causes stuttering when it's direct capturing. This might be a nvfbc bug. This does not happen when using a compositor.
direct_capture = false;
fprintf(stderr, "Warning: screen-direct has temporary been disabled as it causes stuttering. This is likely a NvFBC bug. Falling back to \"screen\".\n");
}
if(strcmp(window_str.c_str(), "screen-direct-force") == 0) {
direct_capture = true;
capture_target = "screen";
fprintf(stderr, "Warning: %s capture option is not recommended unless you use G-SYNC as Nvidia has driver issues that can cause your system or games to freeze/crash.\n", window_str.c_str());
}
gsr_capture_nvfbc_params nvfbc_params;