aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/utils.h5
-rw-r--r--src/capture/kms.c4
-rw-r--r--src/main.cpp121
-rw-r--r--src/utils.c28
4 files changed, 102 insertions, 56 deletions
diff --git a/include/utils.h b/include/utils.h
index d3af640..d8fa99a 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -41,9 +41,9 @@ bool generate_random_characters_standard_alphabet(char *buffer, int buffer_size)
typedef void (*active_monitor_callback)(const gsr_monitor *monitor, void *userdata);
void for_each_active_monitor_output_x11_not_cached(Display *display, active_monitor_callback callback, void *userdata);
-void for_each_active_monitor_output(const gsr_egl *egl, gsr_connection_type connection_type, active_monitor_callback callback, void *userdata);
+void for_each_active_monitor_output(const gsr_window *window, const char *card_path, gsr_connection_type connection_type, active_monitor_callback callback, void *userdata);
bool get_monitor_by_name(const gsr_egl *egl, gsr_connection_type connection_type, const char *name, gsr_monitor *monitor);
-gsr_monitor_rotation drm_monitor_get_display_server_rotation(const gsr_egl *egl, const gsr_monitor *monitor);
+gsr_monitor_rotation drm_monitor_get_display_server_rotation(const gsr_window *window, const gsr_monitor *monitor);
int get_connector_type_by_name(const char *name);
drm_connector_type_count* drm_connector_types_get_index(drm_connector_type_count *type_counts, int *num_type_counts, int connector_type);
@@ -52,6 +52,7 @@ uint32_t monitor_identifier_from_type_and_count(int monitor_type_index, int moni
bool gl_get_gpu_info(gsr_egl *egl, gsr_gpu_info *info);
bool gl_driver_version_greater_than(const gsr_egl *egl, int major, int minor, int patch);
+bool try_card_has_valid_plane(const char *card_path);
/* |output| should be at least 128 bytes in size */
bool gsr_get_valid_card_path(gsr_egl *egl, char *output, bool is_monitor_capture);
/* |render_path| should be at least 128 bytes in size */
diff --git a/src/capture/kms.c b/src/capture/kms.c
index d692929..27ddec4 100644
--- a/src/capture/kms.c
+++ b/src/capture/kms.c
@@ -196,7 +196,7 @@ static int gsr_capture_kms_start(gsr_capture *cap, AVCodecContext *video_codec_c
self->params.display_to_capture, strlen(self->params.display_to_capture),
0,
};
- for_each_active_monitor_output(self->params.egl, connection_type, monitor_callback, &monitor_callback_userdata);
+ for_each_active_monitor_output(self->params.egl->window, self->params.egl->card_path, connection_type, monitor_callback, &monitor_callback_userdata);
if(!get_monitor_by_name(self->params.egl, connection_type, self->params.display_to_capture, &monitor)) {
fprintf(stderr, "gsr error: gsr_capture_kms_start: failed to find monitor by name \"%s\"\n", self->params.display_to_capture);
@@ -205,7 +205,7 @@ static int gsr_capture_kms_start(gsr_capture *cap, AVCodecContext *video_codec_c
}
monitor.name = self->params.display_to_capture;
- self->monitor_rotation = drm_monitor_get_display_server_rotation(self->params.egl, &monitor);
+ self->monitor_rotation = drm_monitor_get_display_server_rotation(self->params.egl->window, &monitor);
self->capture_pos = monitor.pos;
/* Monitor size is already rotated on x11 when the monitor is rotated, no need to apply it ourselves */
diff --git a/src/main.cpp b/src/main.cpp
index 119da89..fbdb6b1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1069,7 +1069,7 @@ static void open_video_hardware(AVCodecContext *codec_context, VideoQuality vide
static void usage_header() {
const bool inside_flatpak = getenv("FLATPAK_ID") != NULL;
const char *program_name = inside_flatpak ? "flatpak run --command=gpu-screen-recorder com.dec05eba.gpu_screen_recorder" : "gpu-screen-recorder";
- printf("usage: %s -w <window_id|monitor|focused|portal> [-c <container_format>] [-s WxH] -f <fps> [-a <audio_input>] [-q <quality>] [-r <replay_buffer_size_sec>] [-k h264|hevc|av1|vp8|vp9|hevc_hdr|av1_hdr|hevc_10bit|av1_10bit] [-ac aac|opus|flac] [-ab <bitrate>] [-oc yes|no] [-fm cfr|vfr|content] [-bm auto|qp|vbr|cbr] [-cr limited|full] [-df yes|no] [-sc <script_path>] [-cursor yes|no] [-keyint <value>] [-restore-portal-session yes|no] [-portal-session-token-filepath filepath] [-encoder gpu|cpu] [-o <output_file>] [-v yes|no] [--version] [-h|--help]\n", program_name);
+ printf("usage: %s -w <window_id|monitor|focused|portal> [-c <container_format>] [-s WxH] -f <fps> [-a <audio_input>] [-q <quality>] [-r <replay_buffer_size_sec>] [-k h264|hevc|av1|vp8|vp9|hevc_hdr|av1_hdr|hevc_10bit|av1_10bit] [-ac aac|opus|flac] [-ab <bitrate>] [-oc yes|no] [-fm cfr|vfr|content] [-bm auto|qp|vbr|cbr] [-cr limited|full] [-df yes|no] [-sc <script_path>] [-cursor yes|no] [-keyint <value>] [-restore-portal-session yes|no] [-portal-session-token-filepath filepath] [-encoder gpu|cpu] [-o <output_file>] [--list-capture-options [card_path] [vendor]] [--list-audio-devices] [--list-application-audio] [-v yes|no] [--version] [-h|--help]\n", program_name);
fflush(stdout);
}
@@ -1204,6 +1204,7 @@ static void usage_full() {
printf(" window\n");
printf(" DP-1|1920x1080\n");
printf(" The <option> and <monitor_name> is the name that can be passed to GPU Screen Recorder with the -w option.\n");
+ printf(" --list-capture-options optionally accepts a card path (\"/dev/dri/cardN\") and vendor (\"amd\", \"intel\" or \"nvidia\") which can improve the performance of running this command.\n");
printf("\n");
printf(" --list-audio-devices\n");
printf(" List audio devices. Lists audio devices in the following format (prints them to stdout and exits):\n");
@@ -1939,6 +1940,7 @@ static void list_gpu_info(gsr_egl *egl) {
printf("vendor|nvidia\n");
break;
}
+ printf("card_path|%s\n", egl->card_path);
}
static const AVCodec* get_ffmpeg_video_codec(VideoCodec video_codec, gsr_gpu_vendor vendor) {
@@ -2037,19 +2039,19 @@ static void list_supported_video_codecs(gsr_egl *egl, bool wayland) {
// puts("hevc_vulkan"); // TODO: hdr, 10 bit
}
-static bool monitor_capture_use_drm(gsr_egl *egl) {
- return gsr_window_get_display_server(egl->window) == GSR_DISPLAY_SERVER_WAYLAND || egl->gpu_info.vendor != GSR_GPU_VENDOR_NVIDIA;
+static bool monitor_capture_use_drm(const gsr_window *window, gsr_gpu_vendor vendor) {
+ return gsr_window_get_display_server(window) == GSR_DISPLAY_SERVER_WAYLAND || vendor != GSR_GPU_VENDOR_NVIDIA;
}
typedef struct {
- gsr_egl *egl;
+ const gsr_window *window;
} capture_options_callback;
static void output_monitor_info(const gsr_monitor *monitor, void *userdata) {
const capture_options_callback *options = (capture_options_callback*)userdata;
- if(gsr_window_get_display_server(options->egl->window) == GSR_DISPLAY_SERVER_WAYLAND) {
+ if(gsr_window_get_display_server(options->window) == GSR_DISPLAY_SERVER_WAYLAND) {
vec2i monitor_size = monitor->size;
- const gsr_monitor_rotation rot = drm_monitor_get_display_server_rotation(options->egl, monitor);
+ const gsr_monitor_rotation rot = drm_monitor_get_display_server_rotation(options->window, monitor);
if(rot == GSR_MONITOR_ROT_90 || rot == GSR_MONITOR_ROT_270)
std::swap(monitor_size.x, monitor_size.y);
printf("%.*s|%dx%d\n", monitor->name_len, monitor->name, monitor_size.x, monitor_size.y);
@@ -2058,8 +2060,8 @@ static void output_monitor_info(const gsr_monitor *monitor, void *userdata) {
}
}
-static void list_supported_capture_options(gsr_egl *egl, bool list_monitors) {
- const bool wayland = gsr_window_get_display_server(egl->window) == GSR_DISPLAY_SERVER_WAYLAND;
+static void list_supported_capture_options(const gsr_window *window, const char *card_path, gsr_gpu_vendor vendor, bool list_monitors) {
+ const bool wayland = gsr_window_get_display_server(window) == GSR_DISPLAY_SERVER_WAYLAND;
if(!wayland) {
puts("window");
puts("focused");
@@ -2067,14 +2069,14 @@ static void list_supported_capture_options(gsr_egl *egl, bool list_monitors) {
if(list_monitors) {
capture_options_callback options;
- options.egl = egl;
- if(monitor_capture_use_drm(egl)) {
- const bool is_x11 = gsr_window_get_display_server(egl->window) == GSR_DISPLAY_SERVER_X11;
+ 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(egl, connection_type, output_monitor_info, &options);
+ 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(egl, GSR_CONNECTION_X11, output_monitor_info, &options);
+ for_each_active_monitor_output(window, card_path, GSR_CONNECTION_X11, output_monitor_info, &options);
}
}
@@ -2132,7 +2134,7 @@ static void info_command() {
bool list_monitors = true;
egl.card_path[0] = '\0';
- if(monitor_capture_use_drm(&egl)) {
+ if(monitor_capture_use_drm(window, egl.gpu_info.vendor)) {
// TODO: Allow specifying another card, and in other places
if(!gsr_get_valid_card_path(&egl, egl.card_path, true)) {
fprintf(stderr, "Error: no /dev/dri/cardX device found. Make sure that you have at least one monitor connected\n");
@@ -2153,12 +2155,13 @@ static void info_command() {
puts("section=video_codecs");
list_supported_video_codecs(&egl, wayland);
puts("section=capture_options");
- list_supported_capture_options(&egl, list_monitors);
+ list_supported_capture_options(window, egl.card_path, egl.gpu_info.vendor, list_monitors);
fflush(stdout);
// Not needed as this will just slow down shutdown
//gsr_egl_unload(&egl);
+ //gsr_window_destroy(&window);
//if(dpy)
// XCloseDisplay(dpy);
@@ -2202,7 +2205,8 @@ static void list_application_audio_command() {
_exit(0);
}
-static void list_capture_options_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) {
bool wayland = false;
Display *dpy = XOpenDisplay(nullptr);
if (!dpy) {
@@ -2230,35 +2234,53 @@ static void list_capture_options_command() {
_exit(1);
}
- gsr_egl egl;
- if(!gsr_egl_load(&egl, window, false)) {
- fprintf(stderr, "gsr error: failed to load opengl\n");
- _exit(1);
- }
+ if(card_path) {
+ list_supported_capture_options(window, card_path, vendor, true);
+ } else {
+ gsr_egl egl;
+ if(!gsr_egl_load(&egl, window, false)) {
+ fprintf(stderr, "gsr error: failed to load opengl\n");
+ _exit(1);
+ }
- bool list_monitors = true;
- egl.card_path[0] = '\0';
- if(monitor_capture_use_drm(&egl)) {
- // TODO: Allow specifying another card, and in other places
- if(!gsr_get_valid_card_path(&egl, egl.card_path, true)) {
- fprintf(stderr, "Error: no /dev/dri/cardX device found. Make sure that you have at least one monitor connected\n");
- list_monitors = false;
+ bool list_monitors = true;
+ egl.card_path[0] = '\0';
+ if(monitor_capture_use_drm(window, egl.gpu_info.vendor)) {
+ // TODO: Allow specifying another card, and in other places
+ if(!gsr_get_valid_card_path(&egl, egl.card_path, true)) {
+ fprintf(stderr, "Error: no /dev/dri/cardX device found. Make sure that you have at least one monitor connected\n");
+ list_monitors = false;
+ }
}
+ list_supported_capture_options(window, egl.card_path, egl.gpu_info.vendor, list_monitors);
}
- av_log_set_level(AV_LOG_FATAL);
- list_supported_capture_options(&egl, list_monitors);
-
fflush(stdout);
// Not needed as this will just slow down shutdown
//gsr_egl_unload(&egl);
+ //gsr_window_destroy(&window);
//if(dpy)
// XCloseDisplay(dpy);
_exit(0);
}
+static bool gpu_vendor_from_string(const char *vendor_str, gsr_gpu_vendor *vendor) {
+ if(strcmp(vendor_str, "amd") == 0) {
+ *vendor = GSR_GPU_VENDOR_AMD;
+ return true;
+ } else if(strcmp(vendor_str, "intel") == 0) {
+ *vendor = GSR_GPU_VENDOR_INTEL;
+ return true;
+ } else if(strcmp(vendor_str, "nvidia") == 0) {
+ *vendor = GSR_GPU_VENDOR_NVIDIA;
+ return true;
+ } else {
+ return false;
+ }
+}
+
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)
@@ -2303,14 +2325,14 @@ 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)) {
+ 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, connection_type, get_first_output, &first_output);
+ 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;
@@ -2323,7 +2345,7 @@ static gsr_capture* create_capture_impl(std::string &window_str, vec2i output_re
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, connection_type, monitor_output_callback_print, NULL);
+ for_each_active_monitor_output(egl->window, egl->card_path, connection_type, monitor_output_callback_print, NULL);
_exit(1);
}
}
@@ -2338,7 +2360,7 @@ static gsr_capture* create_capture_impl(std::string &window_str, vec2i output_re
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, GSR_CONNECTION_X11, monitor_output_callback_print, NULL);
+ for_each_active_monitor_output(egl->window, egl->card_path, GSR_CONNECTION_X11, monitor_output_callback_print, NULL);
_exit(1);
}
}
@@ -3015,9 +3037,30 @@ int main(int argc, char **argv) {
_exit(0);
}
- if(argc == 2 && strcmp(argv[1], "--list-capture-options") == 0) {
- list_capture_options_command();
- _exit(0);
+ if(strcmp(argv[1], "--list-capture-options") == 0) {
+ if(argc == 2) {
+ list_capture_options_command(nullptr, GSR_GPU_VENDOR_AMD);
+ _exit(0);
+ } else if(argc == 4) {
+ const char *card_path = argv[2];
+ if(!try_card_has_valid_plane(card_path)) {
+ fprintf(stderr, "Error: \"%s\" is not a valid /dev/dri/cardN card. Make sure that you have at least one monitor connected\n", card_path);
+ _exit(1);
+ }
+
+ const char *vendor_str = argv[3];
+ gsr_gpu_vendor vendor;
+ if(!gpu_vendor_from_string(vendor_str, &vendor)) {
+ fprintf(stderr, "Error: \"%s\" is not a valid vendor, expected \"amd\", \"intel\" or \"nvidia\"\n", vendor_str);
+ _exit(1);
+ }
+
+ list_capture_options_command(card_path, vendor);
+ _exit(0);
+ } else {
+ fprintf(stderr, "Error: expected --list-capture-options to be called with either no extra arguments or 2 extra arguments (card path and vendor)\n");
+ _exit(1);
+ }
}
if(argc == 2 && strcmp(argv[1], "--version") == 0) {
@@ -3421,7 +3464,7 @@ int main(int argc, char **argv) {
}
egl.card_path[0] = '\0';
- if(monitor_capture_use_drm(&egl)) {
+ if(monitor_capture_use_drm(window, egl.gpu_info.vendor)) {
// TODO: Allow specifying another card, and in other places
if(!gsr_get_valid_card_path(&egl, egl.card_path, is_monitor_capture)) {
fprintf(stderr, "Error: no /dev/dri/cardX device found. Make sure that you have at least one monitor connected or record a single window instead on X11 or record with the -w portal option\n");
diff --git a/src/utils.c b/src/utils.c
index d14dd23..9295541 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -188,10 +188,12 @@ static bool connector_get_property_by_name(int drmfd, drmModeConnectorPtr props,
return false;
}
-static void for_each_active_monitor_output_drm(const gsr_egl *egl, active_monitor_callback callback, void *userdata) {
- int fd = open(egl->card_path, O_RDONLY);
- if(fd == -1)
+static void for_each_active_monitor_output_drm(const char *card_path, active_monitor_callback callback, void *userdata) {
+ int fd = open(card_path, O_RDONLY);
+ if(fd == -1) {
+ fprintf(stderr, "gsr error: for_each_active_monitor_output_drm failed, failed to open \"%s\", error: %s\n", card_path, strerror(errno));
return;
+ }
drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1);
@@ -250,14 +252,14 @@ static void for_each_active_monitor_output_drm(const gsr_egl *egl, active_monito
close(fd);
}
-void for_each_active_monitor_output(const gsr_egl *egl, gsr_connection_type connection_type, active_monitor_callback callback, void *userdata) {
+void for_each_active_monitor_output(const gsr_window *window, const char *card_path, gsr_connection_type connection_type, active_monitor_callback callback, void *userdata) {
switch(connection_type) {
case GSR_CONNECTION_X11:
case GSR_CONNECTION_WAYLAND:
- gsr_window_for_each_active_monitor_output_cached(egl->window, callback, userdata);
+ gsr_window_for_each_active_monitor_output_cached(window, callback, userdata);
break;
case GSR_CONNECTION_DRM:
- for_each_active_monitor_output_drm(egl, callback, userdata);
+ for_each_active_monitor_output_drm(card_path, callback, userdata);
break;
}
}
@@ -280,7 +282,7 @@ bool get_monitor_by_name(const gsr_egl *egl, gsr_connection_type connection_type
userdata.name_len = strlen(name);
userdata.monitor = monitor;
userdata.found_monitor = false;
- for_each_active_monitor_output(egl, connection_type, get_monitor_by_name_callback, &userdata);
+ for_each_active_monitor_output(egl->window, egl->card_path, connection_type, get_monitor_by_name_callback, &userdata);
return userdata.found_monitor;
}
@@ -312,14 +314,14 @@ static void get_monitor_by_connector_id_callback(const gsr_monitor *monitor, voi
}
}
-gsr_monitor_rotation drm_monitor_get_display_server_rotation(const gsr_egl *egl, const gsr_monitor *monitor) {
- if(gsr_window_get_display_server(egl->window) == GSR_DISPLAY_SERVER_WAYLAND) {
+gsr_monitor_rotation drm_monitor_get_display_server_rotation(const gsr_window *window, const gsr_monitor *monitor) {
+ if(gsr_window_get_display_server(window) == GSR_DISPLAY_SERVER_WAYLAND) {
{
get_monitor_by_connector_id_userdata userdata;
userdata.monitor = monitor;
userdata.rotation = GSR_MONITOR_ROT_0;
userdata.match_found = false;
- gsr_window_for_each_active_monitor_output_cached(egl->window, get_monitor_by_name_and_size_callback, &userdata);
+ gsr_window_for_each_active_monitor_output_cached(window, get_monitor_by_name_and_size_callback, &userdata);
if(userdata.match_found)
return userdata.rotation;
}
@@ -328,7 +330,7 @@ gsr_monitor_rotation drm_monitor_get_display_server_rotation(const gsr_egl *egl,
userdata.monitor = monitor;
userdata.rotation = GSR_MONITOR_ROT_0;
userdata.match_found = false;
- gsr_window_for_each_active_monitor_output_cached(egl->window, get_monitor_by_connector_id_callback, &userdata);
+ gsr_window_for_each_active_monitor_output_cached(window, get_monitor_by_connector_id_callback, &userdata);
return userdata.rotation;
}
} else {
@@ -336,7 +338,7 @@ gsr_monitor_rotation drm_monitor_get_display_server_rotation(const gsr_egl *egl,
userdata.monitor = monitor;
userdata.rotation = GSR_MONITOR_ROT_0;
userdata.match_found = false;
- gsr_window_for_each_active_monitor_output_cached(egl->window, get_monitor_by_connector_id_callback, &userdata);
+ gsr_window_for_each_active_monitor_output_cached(window, get_monitor_by_connector_id_callback, &userdata);
return userdata.rotation;
}
@@ -419,7 +421,7 @@ bool gl_driver_version_greater_than(const gsr_egl *egl, int major, int minor, in
return version_greater_than(egl->gpu_info.driver_major, egl->gpu_info.driver_minor, egl->gpu_info.driver_patch, major, minor, patch);
}
-static bool try_card_has_valid_plane(const char *card_path) {
+bool try_card_has_valid_plane(const char *card_path) {
drmVersion *ver = NULL;
drmModePlaneResPtr planes = NULL;
bool found_screen_card = false;