From 58299fbb24f4b44c9d11ec8b4d9a1878d2280dea Mon Sep 17 00:00:00 2001 From: dec05eba Date: Fri, 17 Mar 2023 18:35:16 +0100 Subject: Add overclocking option to workaround a NVIDIA driver bug (forcefully set to p2 state when using cuda) --- README.md | 14 ++++-- com.dec05eba.gpu_screen_recorder.appdata.xml | 5 ++ src/config.hpp | 14 ++++++ src/main.cpp | 70 +++++++++++++++++++++++++++- 4 files changed, 98 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 90499d2..26d050b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -gtk frontend for [gpu-screen-recorder](https://git.dec05eba.com/gpu-screen-recorder/). +gtk frontend for [gpu-screen-recorder](https://git.dec05eba.com/gpu-screen-recorder/about/). This is a screen recorder that has minimal impact on system performance by recording a window using the GPU only, similar to shadowplay on windows. This is the fastest screen recording tool for Linux. @@ -6,7 +6,7 @@ similar to shadowplay on windows. This is the fastest screen recording tool for This screen recorder can be used for recording your desktop offline, for live streaming and for nvidia shadowplay-like instant replay, where only the last few seconds are saved. -More info at [gpu-screen-recorder](https://git.dec05eba.com/gpu-screen-recorder/). +More info at [gpu-screen-recorder](https://git.dec05eba.com/gpu-screen-recorder/about/). ## Note This software works only on x11 and with an nvidia gpu.\ @@ -15,11 +15,19 @@ For screen capture to work with PRIME (laptops with a nvidia gpu), you must set ![](https://dec05eba.com/images/nvidia-settings-prime.png)\ and then rebooting your laptop. +# Performance +When recording Legend of Zelda Breath of the Wild at 4k, fps drops from 30 to 7 when using OBS Studio + nvenc, however when using this screen recorder the fps remains at 30.\ +When recording GTA V at 4k on highest settings, fps drops from 60 to 23 when using obs-nvfbc + nvenc, however when using this screen recorder the fps only drops to 58. The quality is also much better when using gpu-screen-recorder.\ +It is recommended to save the video to a SSD because of the large file size, which a slow HDD might not be fast enough to handle. +## Note about optimal performance on NVIDIA +NVIDIA driver has a "feature" (read: bug) where it will downclock memory transfer rate when a program uses cuda, such as GPU Screen Recorder. See https://git.dec05eba.com/gpu-screen-recorder/about/ for more information and how to overcome this. + ## Installation This program depends on [gpu-screen-recorder](https://git.dec05eba.com/gpu-screen-recorder/) which needs to be installed first.\ Run `./install.sh` as root or if you are running Arch Linux, then you can find gpu screen recorder gtk on aur under the name gpu-screen-recorder-gtk-git (`yay -S gpu-screen-recorder-gtk-git`).\ Dependencies needed when building using `build.sh` or `install.sh`: `gtk3 libx11 libxrandr libpulse libglvnd (which provides libgl and libegl)`.\ -You can also install gpu screen recorder (the gtk gui version) from [flathub](https://flathub.org/apps/details/com.dec05eba.gpu_screen_recorder). This flatpak includes gpu-screen-recorder so no need to install that first. +You can also install gpu screen recorder (the gtk gui version) from [flathub](https://flathub.org/apps/details/com.dec05eba.gpu_screen_recorder). This flatpak includes gpu-screen-recorder so no need to install that first.\ +Note that if you use the flatpak version then you wont be able to use overclocking unless you set "Coolbits" NVIDIA X setting. See https://git.dec05eba.com/gpu-screen-recorder/about/ for more information and how to overcome this. ## Screenshots ![](https://www.dec05eba.com/images/gpu-screen-recorder.png) diff --git a/com.dec05eba.gpu_screen_recorder.appdata.xml b/com.dec05eba.gpu_screen_recorder.appdata.xml index b8c1bfe..5704b2b 100644 --- a/com.dec05eba.gpu_screen_recorder.appdata.xml +++ b/com.dec05eba.gpu_screen_recorder.appdata.xml @@ -33,6 +33,11 @@ + + +

Add option to workaround a NVIDIA driver "bug" that causes framerate to drop a bit when recording (overclock memory transfer rate back to normal)

+
+

Make it clear when graphics card is not supported

diff --git a/src/config.hpp b/src/config.hpp index bd43166..275f9f9 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -26,6 +26,8 @@ struct MainConfig { std::string quality; std::string codec; // Video codec std::string audio_codec; + bool advanced_view = false; + bool overclock = false; }; struct StreamingConfig { @@ -245,6 +247,16 @@ static Config read_config() { config.main_config.codec.assign(value.str, value.size); } else if(key == "main.audio_codec") { config.main_config.audio_codec.assign(value.str, value.size); + } else if(key == "main.advanced_view") { + if(value == "true") + config.main_config.advanced_view = true; + else if(value == "false") + config.main_config.advanced_view = false; + } else if(key == "main.overclock") { + if(value == "true") + config.main_config.overclock = true; + else if(value == "false") + config.main_config.overclock = false; } else if(key == "streaming.service") { config.streaming_config.streaming_service.assign(value.str, value.size); } else if(key == "streaming.key") { @@ -329,6 +341,8 @@ static void save_config(const Config &config) { fprintf(file, "main.quality %s\n", config.main_config.quality.c_str()); fprintf(file, "main.codec %s\n", config.main_config.codec.c_str()); fprintf(file, "main.audio_codec %s\n", config.main_config.audio_codec.c_str()); + fprintf(file, "main.advanced_view %s\n", config.main_config.advanced_view ? "true" : "false"); + fprintf(file, "main.overclock %s\n", config.main_config.overclock ? "true" : "false"); fprintf(file, "streaming.service %s\n", config.streaming_config.streaming_service.c_str()); fprintf(file, "streaming.key %s\n", config.streaming_config.stream_key.c_str()); diff --git a/src/main.cpp b/src/main.cpp index a67d868..4f063cd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -76,6 +76,11 @@ static GtkWidget *replay_start_stop_hotkey_button; static GtkWidget *replay_save_hotkey_button; static GtkWidget *streaming_hotkey_button; static GtkWidget *merge_audio_tracks_button; +static GtkGrid *video_codec_grid; +static GtkGrid *audio_codec_grid; +static GtkComboBoxText *view_combo_box; +static GtkGrid *overclock_grid; +static GtkWidget *overclock_button; static XIM xim; static XIC xic; @@ -364,6 +369,8 @@ static void save_configs() { config.main_config.quality = gtk_combo_box_get_active_id(GTK_COMBO_BOX(quality_input_menu)); config.main_config.codec = gtk_combo_box_get_active_id(GTK_COMBO_BOX(video_codec_input_menu)); config.main_config.audio_codec = gtk_combo_box_get_active_id(GTK_COMBO_BOX(audio_codec_input_menu)); + config.main_config.advanced_view = strcmp(gtk_combo_box_get_active_id(GTK_COMBO_BOX(view_combo_box)), "advanced") == 0; + config.main_config.overclock = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(overclock_button)); config.streaming_config.streaming_service = gtk_combo_box_get_active_id(GTK_COMBO_BOX(stream_service_input_menu)); config.streaming_config.stream_key = gtk_entry_get_text(stream_id_entry); @@ -1003,6 +1010,9 @@ static gboolean on_start_replay_button_click(GtkButton *button, gpointer userdat "gpu-screen-recorder", "-w", window_str.c_str(), "-c", container_str, "-q", quality_input_str, "-k", video_codec_input_str, "-ac", audio_codec_input_str, "-f", fps_str.c_str(), "-r", replay_time_str.c_str(), "-o", dir }; + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(overclock_button))) + args.insert(args.end(), { "-oc", "yes" }); + std::string merge_audio_tracks_arg_value; if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(merge_audio_tracks_button))) { for_each_used_audio_input(GTK_LIST_BOX(audio_input_used_list), [&merge_audio_tracks_arg_value](const AudioRow *audio_row) { @@ -1123,6 +1133,9 @@ static gboolean on_start_recording_button_click(GtkButton *button, gpointer user "gpu-screen-recorder", "-w", window_str.c_str(), "-c", container_str, "-q", quality_input_str, "-k", video_codec_input_str, "-ac", audio_codec_input_str, "-f", fps_str.c_str(), "-o", record_file_current_filename.c_str() }; + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(overclock_button))) + args.insert(args.end(), { "-oc", "yes" }); + std::string merge_audio_tracks_arg_value; if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(merge_audio_tracks_button))) { for_each_used_audio_input(GTK_LIST_BOX(audio_input_used_list), [&merge_audio_tracks_arg_value](const AudioRow *audio_row) { @@ -1243,6 +1256,9 @@ static gboolean on_start_streaming_button_click(GtkButton *button, gpointer user "gpu-screen-recorder", "-w", window_str.c_str(), "-c", "flv", "-q", quality_input_str, "-k", video_codec_input_str, "-ac", audio_codec_input_str, "-f", fps_str.c_str(), "-o", stream_url.c_str() }; + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(overclock_button))) + args.insert(args.end(), { "-oc", "yes" }); + std::string merge_audio_tracks_arg_value; if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(merge_audio_tracks_button))) { for_each_used_audio_input(GTK_LIST_BOX(audio_input_used_list), [&merge_audio_tracks_arg_value](const AudioRow *audio_row) { @@ -1442,6 +1458,14 @@ static void record_area_item_change_callback(GtkComboBox *widget, gpointer userd enable_stream_record_button_if_info_filled(); } +static void view_combo_box_change_callback(GtkComboBox *widget, gpointer userdata) { + (void)userdata; + const gchar *selected_view = gtk_combo_box_get_active_id(widget); + gtk_widget_set_visible(GTK_WIDGET(video_codec_grid), strcmp(selected_view, "advanced") == 0); + gtk_widget_set_visible(GTK_WIDGET(audio_codec_grid), strcmp(selected_view, "advanced") == 0); + gtk_widget_set_visible(GTK_WIDGET(overclock_grid), strcmp(selected_view, "advanced") == 0); +} + static void stream_service_item_change_callback(GtkComboBox *widget, gpointer userdata) { (void)userdata; const gchar *selected_stream_service = gtk_combo_box_get_active_id(widget); @@ -1645,6 +1669,17 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a int record_area_row = 0; int audio_input_area_row = 0; + GtkGrid *simple_advanced_grid = GTK_GRID(gtk_grid_new()); + gtk_grid_attach(grid, GTK_WIDGET(simple_advanced_grid), 0, grid_row++, 2, 1); + gtk_grid_attach(simple_advanced_grid, gtk_label_new("View: "), 0, 0, 1, 1); + view_combo_box = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); + gtk_combo_box_text_append(view_combo_box, "simple", "Simple"); + gtk_combo_box_text_append(view_combo_box, "advanced", "Advanced"); + gtk_widget_set_hexpand(GTK_WIDGET(view_combo_box), true); + gtk_grid_attach(simple_advanced_grid, GTK_WIDGET(view_combo_box), 1, 0, 1, 1); + gtk_combo_box_set_active(GTK_COMBO_BOX(view_combo_box), 0); + g_signal_connect(view_combo_box, "changed", G_CALLBACK(view_combo_box_change_callback), view_combo_box); + GtkFrame *record_area_frame = GTK_FRAME(gtk_frame_new("Record area")); gtk_grid_attach(grid, GTK_WIDGET(record_area_frame), 0, grid_row++, 2, 1); @@ -1815,7 +1850,7 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a gtk_grid_attach(quality_grid, GTK_WIDGET(quality_input_menu), 1, 0, 1, 1); gtk_combo_box_set_active(GTK_COMBO_BOX(quality_input_menu), 0); - GtkGrid *video_codec_grid = GTK_GRID(gtk_grid_new()); + video_codec_grid = GTK_GRID(gtk_grid_new()); gtk_grid_attach(grid, GTK_WIDGET(video_codec_grid), 0, grid_row++, 2, 1); gtk_grid_attach(video_codec_grid, gtk_label_new("Video codec: "), 0, 0, 1, 1); video_codec_input_menu = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); @@ -1826,7 +1861,7 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a gtk_grid_attach(video_codec_grid, GTK_WIDGET(video_codec_input_menu), 1, 0, 1, 1); gtk_combo_box_set_active(GTK_COMBO_BOX(video_codec_input_menu), 0); - GtkGrid *audio_codec_grid = GTK_GRID(gtk_grid_new()); + audio_codec_grid = GTK_GRID(gtk_grid_new()); gtk_grid_attach(grid, GTK_WIDGET(audio_codec_grid), 0, grid_row++, 2, 1); gtk_grid_attach(audio_codec_grid, gtk_label_new("Audio codec: "), 0, 0, 1, 1); audio_codec_input_menu = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); @@ -1837,6 +1872,34 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a gtk_grid_attach(audio_codec_grid, GTK_WIDGET(audio_codec_input_menu), 1, 0, 1, 1); gtk_combo_box_set_active(GTK_COMBO_BOX(audio_codec_input_menu), 0); + // TODO: Hide this when gpu is not NVIDIA + overclock_grid = GTK_GRID(gtk_grid_new()); + gtk_grid_attach(grid, GTK_WIDGET(overclock_grid), 0, grid_row++, 2, 1); + overclock_button = gtk_check_button_new_with_label("Overclock memory transfer rate to workaround NVIDIA driver performance bug"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(overclock_button), false); + gtk_widget_set_halign(overclock_button, GTK_ALIGN_START); + gtk_grid_attach(overclock_grid, overclock_button, 0, 0, 1, 1); + GtkButton *overclock_info_button = GTK_BUTTON(gtk_button_new_with_label("?")); + gtk_grid_attach(overclock_grid, GTK_WIDGET(overclock_info_button), 1, 0, 1, 1); + + g_signal_connect(overclock_info_button, "clicked", G_CALLBACK(+[](GtkButton *button, gpointer userdata){ + (void)button; + (void)userdata; + GtkWidget *dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + "NVIDIA driver has a \"feature\" (read: bug) where it will downclock memory transfer rate when a program uses CUDA, such as GPU Screen Recorder.\n" + "To work around this bug, GPU Screen Recorder can overclock your GPU memory transfer rate to it's normal optimal level. To enable overclocking for optimal performance enable the \"Overclock memory transfer rate to workaround NVIDIA driver performance bug\" option.\n" + "You also need to have \"Coolbits\" NVIDIA X setting set to \"12\" to enable overclocking. This setting is automatically installed if you installed GPU Screen Recorder from AUR or from source, but not if you installed GPU Screen Recorder flatpak.\n" + "Click here to see how to set this up manually or if you are using flatpak.\n" + "\n" + "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.\n" + "\n" + "Obs! use at your own risk!"); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + return true; + }), nullptr); + GtkGrid *start_button_grid = GTK_GRID(gtk_grid_new()); gtk_grid_attach(grid, GTK_WIDGET(start_button_grid), 0, grid_row++, 2, 1); gtk_grid_set_column_spacing(start_button_grid, 10); @@ -2226,6 +2289,7 @@ static void load_config() { gtk_combo_box_set_active_id(GTK_COMBO_BOX(quality_input_menu), config.main_config.quality.c_str()); gtk_combo_box_set_active_id(GTK_COMBO_BOX(video_codec_input_menu), config.main_config.codec.c_str()); gtk_combo_box_set_active_id(GTK_COMBO_BOX(audio_codec_input_menu), config.main_config.audio_codec.c_str()); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(overclock_button), config.main_config.overclock); gtk_combo_box_set_active_id(GTK_COMBO_BOX(stream_service_input_menu), config.streaming_config.streaming_service.c_str()); gtk_entry_set_text(stream_id_entry, config.streaming_config.stream_key.c_str()); @@ -2257,6 +2321,8 @@ static void load_config() { set_hotkey_text_from_hotkey_data(GTK_ENTRY(replay_save_hotkey_button), replay_save_hotkey); } + gtk_combo_box_set_active_id(GTK_COMBO_BOX(view_combo_box), config.main_config.advanced_view ? "advanced" : "simple"); + view_combo_box_change_callback(GTK_COMBO_BOX(view_combo_box), view_combo_box); enable_stream_record_button_if_info_filled(); } -- cgit v1.2.3