aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild.sh9
-rw-r--r--external/wlr-export-dmabuf-unstable-v1.xml203
-rw-r--r--src/egl.c20
-rw-r--r--src/egl.h6
-rw-r--r--src/main.cpp60
5 files changed, 24 insertions, 274 deletions
diff --git a/build.sh b/build.sh
index 9327b62..fabf40b 100755
--- a/build.sh
+++ b/build.sh
@@ -9,22 +9,15 @@ CXX=${CXX:-g++}
opts="-O2 -g0 -DNDEBUG -Wall -Wextra -Werror -s"
[ -n "$DEBUG" ] && opts="-O0 -g3 -Wall -Wextra -Werror";
-build_wayland_protocol() {
- wayland-scanner private-code external/wlr-export-dmabuf-unstable-v1.xml external/wlr-export-dmabuf-unstable-v1-protocol.c
- wayland-scanner client-header external/wlr-export-dmabuf-unstable-v1.xml external/wlr-export-dmabuf-unstable-v1-client-protocol.h
-}
-
build_gsr_gtk() {
dependencies="gtk+-3.0 x11 xrandr libpulse libcap libdrm wayland-egl wayland-client"
includes="$(pkg-config --cflags $dependencies)"
libs="$(pkg-config --libs $dependencies) -ldl"
$CC -c src/egl.c $opts $includes
$CC -c src/library_loader.c $opts $includes
- $CC -c external/wlr-export-dmabuf-unstable-v1-protocol.c $opts $includes
$CXX -c src/main.cpp $opts $includes
- $CXX -o gpu-screen-recorder-gtk egl.o library_loader.o wlr-export-dmabuf-unstable-v1-protocol.o main.o $libs $opts
+ $CXX -o gpu-screen-recorder-gtk egl.o library_loader.o main.o $libs $opts
}
-build_wayland_protocol
build_gsr_gtk
echo "Successfully built gpu-screen-recorder-gtk"
diff --git a/external/wlr-export-dmabuf-unstable-v1.xml b/external/wlr-export-dmabuf-unstable-v1.xml
deleted file mode 100644
index 2614065..0000000
--- a/external/wlr-export-dmabuf-unstable-v1.xml
+++ /dev/null
@@ -1,203 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<protocol name="wlr_export_dmabuf_unstable_v1">
- <copyright>
- Copyright © 2018 Rostislav Pehlivanov
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sublicense,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice (including the next
- paragraph) shall be included in all copies or substantial portions of the
- Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- DEALINGS IN THE SOFTWARE.
- </copyright>
-
- <description summary="a protocol for low overhead screen content capturing">
- An interface to capture surfaces in an efficient way by exporting DMA-BUFs.
-
- Warning! The protocol described in this file is experimental and
- backward incompatible changes may be made. Backward compatible changes
- may be added together with the corresponding interface version bump.
- Backward incompatible changes are done by bumping the version number in
- the protocol and interface names and resetting the interface version.
- Once the protocol is to be declared stable, the 'z' prefix and the
- version number in the protocol and interface names are removed and the
- interface version number is reset.
- </description>
-
- <interface name="zwlr_export_dmabuf_manager_v1" version="1">
- <description summary="manager to inform clients and begin capturing">
- This object is a manager with which to start capturing from sources.
- </description>
-
- <request name="capture_output">
- <description summary="capture a frame from an output">
- Capture the next frame of a an entire output.
- </description>
- <arg name="frame" type="new_id" interface="zwlr_export_dmabuf_frame_v1"/>
- <arg name="overlay_cursor" type="int"
- summary="include custom client hardware cursor on top of the frame"/>
- <arg name="output" type="object" interface="wl_output"/>
- </request>
-
- <request name="destroy" type="destructor">
- <description summary="destroy the manager">
- All objects created by the manager will still remain valid, until their
- appropriate destroy request has been called.
- </description>
- </request>
- </interface>
-
- <interface name="zwlr_export_dmabuf_frame_v1" version="1">
- <description summary="a DMA-BUF frame">
- This object represents a single DMA-BUF frame.
-
- If the capture is successful, the compositor will first send a "frame"
- event, followed by one or several "object". When the frame is available
- for readout, the "ready" event is sent.
-
- If the capture failed, the "cancel" event is sent. This can happen anytime
- before the "ready" event.
-
- Once either a "ready" or a "cancel" event is received, the client should
- destroy the frame. Once an "object" event is received, the client is
- responsible for closing the associated file descriptor.
-
- All frames are read-only and may not be written into or altered.
- </description>
-
- <enum name="flags">
- <description summary="frame flags">
- Special flags that should be respected by the client.
- </description>
- <entry name="transient" value="0x1"
- summary="clients should copy frame before processing"/>
- </enum>
-
- <event name="frame">
- <description summary="a frame description">
- Main event supplying the client with information about the frame. If the
- capture didn't fail, this event is always emitted first before any other
- events.
-
- This event is followed by a number of "object" as specified by the
- "num_objects" argument.
- </description>
- <arg name="width" type="uint"
- summary="frame width in pixels"/>
- <arg name="height" type="uint"
- summary="frame height in pixels"/>
- <arg name="offset_x" type="uint"
- summary="crop offset for the x axis"/>
- <arg name="offset_y" type="uint"
- summary="crop offset for the y axis"/>
- <arg name="buffer_flags" type="uint"
- summary="flags which indicate properties (invert, interlacing),
- has the same values as zwp_linux_buffer_params_v1:flags"/>
- <arg name="flags" type="uint" enum="flags"
- summary="indicates special frame features"/>
- <arg name="format" type="uint"
- summary="format of the frame (DRM_FORMAT_*)"/>
- <arg name="mod_high" type="uint"
- summary="drm format modifier, high"/>
- <arg name="mod_low" type="uint"
- summary="drm format modifier, low"/>
- <arg name="num_objects" type="uint"
- summary="indicates how many objects (FDs) the frame has (max 4)"/>
- </event>
-
- <event name="object">
- <description summary="an object description">
- Event which serves to supply the client with the file descriptors
- containing the data for each object.
-
- After receiving this event, the client must always close the file
- descriptor as soon as they're done with it and even if the frame fails.
- </description>
- <arg name="index" type="uint"
- summary="index of the current object"/>
- <arg name="fd" type="fd"
- summary="fd of the current object"/>
- <arg name="size" type="uint"
- summary="size in bytes for the current object"/>
- <arg name="offset" type="uint"
- summary="starting point for the data in the object's fd"/>
- <arg name="stride" type="uint"
- summary="line size in bytes"/>
- <arg name="plane_index" type="uint"
- summary="index of the the plane the data in the object applies to"/>
- </event>
-
- <event name="ready">
- <description summary="indicates frame is available for reading">
- This event is sent as soon as the frame is presented, indicating it is
- available for reading. This event includes the time at which
- presentation happened at.
-
- The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples,
- each component being an unsigned 32-bit value. Whole seconds are in
- tv_sec which is a 64-bit value combined from tv_sec_hi and tv_sec_lo,
- and the additional fractional part in tv_nsec as nanoseconds. Hence,
- for valid timestamps tv_nsec must be in [0, 999999999]. The seconds part
- may have an arbitrary offset at start.
-
- After receiving this event, the client should destroy this object.
- </description>
- <arg name="tv_sec_hi" type="uint"
- summary="high 32 bits of the seconds part of the timestamp"/>
- <arg name="tv_sec_lo" type="uint"
- summary="low 32 bits of the seconds part of the timestamp"/>
- <arg name="tv_nsec" type="uint"
- summary="nanoseconds part of the timestamp"/>
- </event>
-
- <enum name="cancel_reason">
- <description summary="cancel reason">
- Indicates reason for cancelling the frame.
- </description>
- <entry name="temporary" value="0"
- summary="temporary error, source will produce more frames"/>
- <entry name="permanent" value="1"
- summary="fatal error, source will not produce frames"/>
- <entry name="resizing" value="2"
- summary="temporary error, source will produce more frames"/>
- </enum>
-
- <event name="cancel">
- <description summary="indicates the frame is no longer valid">
- If the capture failed or if the frame is no longer valid after the
- "frame" event has been emitted, this event will be used to inform the
- client to scrap the frame.
-
- If the failure is temporary, the client may capture again the same
- source. If the failure is permanent, any further attempts to capture the
- same source will fail again.
-
- After receiving this event, the client should destroy this object.
- </description>
- <arg name="reason" type="uint" enum="cancel_reason"
- summary="indicates a reason for cancelling this frame capture"/>
- </event>
-
- <request name="destroy" type="destructor">
- <description summary="delete this object, used or not">
- Unreferences the frame. This request must be called as soon as its no
- longer used.
-
- It can be called at any time by the client. The client will still have
- to close any FDs it has been given.
- </description>
- </request>
- </interface>
-</protocol> \ No newline at end of file
diff --git a/src/egl.c b/src/egl.c
index 0b9affd..0ad9f13 100644
--- a/src/egl.c
+++ b/src/egl.c
@@ -8,7 +8,6 @@
#include <wayland-client.h>
#include <wayland-egl.h>
-#include "../external/wlr-export-dmabuf-unstable-v1-client-protocol.h"
#include <unistd.h>
static void output_handle_geometry(void *data, struct wl_output *wl_output,
@@ -102,12 +101,6 @@ static void registry_add_object(void *data, struct wl_registry *registry, uint32
.name = NULL,
};
wl_output_add_listener(gsr_output->output, &output_listener, gsr_output);
- } else if(strcmp(interface, zwlr_export_dmabuf_manager_v1_interface.name) == 0) {
- if(egl->wayland.export_manager) {
- zwlr_export_dmabuf_manager_v1_destroy(egl->wayland.export_manager);
- egl->wayland.export_manager = NULL;
- }
- egl->wayland.export_manager = wl_registry_bind(registry, name, &zwlr_export_dmabuf_manager_v1_interface, 1);
}
}
@@ -318,11 +311,6 @@ void gsr_egl_unload(gsr_egl *self) {
self->x11.window = None;
}
- if(self->wayland.export_manager) {
- zwlr_export_dmabuf_manager_v1_destroy(self->wayland.export_manager);
- self->wayland.export_manager = NULL;
- }
-
if(self->wayland.window) {
wl_egl_window_destroy(self->wayland.window);
self->wayland.window = NULL;
@@ -373,11 +361,3 @@ void gsr_egl_unload(gsr_egl *self) {
memset(self, 0, sizeof(gsr_egl));
}
-
-bool gsr_egl_supports_wayland_capture(gsr_egl *self) {
- // TODO: wlroots capture is broken right now (black screen) on amd and multiple monitors
- // so it has to be disabled right now. Find out why it happens and fix it.
- (void)self;
- return false;
- //return !!self->wayland.export_manager && self->wayland.num_outputs > 0;
-}
diff --git a/src/egl.h b/src/egl.h
index 5c44760..ab33048 100644
--- a/src/egl.h
+++ b/src/egl.h
@@ -68,10 +68,8 @@ typedef struct {
void *registry;
void *surface;
void *compositor;
- void *export_manager;
gsr_wayland_output outputs[GSR_MAX_OUTPUTS];
int num_outputs;
- gsr_wayland_output *output_to_capture;
} gsr_wayland;
typedef struct {
@@ -84,6 +82,7 @@ typedef struct {
gsr_x11 x11;
gsr_wayland wayland;
+ char card_path[128];
EGLDisplay (*eglGetDisplay)(EGLNativeDisplayType display_id);
unsigned int (*eglInitialize)(EGLDisplay dpy, int32_t *major, int32_t *minor);
@@ -102,7 +101,4 @@ typedef struct {
bool gsr_egl_load(gsr_egl *self, Display *dpy, bool wayland);
void gsr_egl_unload(gsr_egl *self);
-/* wayland protocol capture, does not include kms capture */
-bool gsr_egl_supports_wayland_capture(gsr_egl *self);
-
#endif /* GSR_EGL_H */
diff --git a/src/main.cpp b/src/main.cpp
index 6d89798..8cde7df 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -117,7 +117,6 @@ static std::string record_file_current_filename;
static bool nvfbc_installed = false;
static bool wayland = false;
-static char drm_card_path[128];
static gsr_egl egl;
struct AudioInput {
@@ -664,7 +663,7 @@ static const XRRModeInfo* get_mode_info(const XRRScreenResources *sr, RRMode id)
return NULL;
}
-static void for_each_active_monitor_output_x11(Display *display, active_monitor_callback &callback, void *userdata) {
+static void for_each_active_monitor_output_x11(Display *display, active_monitor_callback callback, void *userdata) {
XRRScreenResources *screen_res = XRRGetScreenResources(display, DefaultRootWindow(display));
if(!screen_res)
return;
@@ -738,10 +737,7 @@ static bool connector_get_property_by_name(int drmfd, drmModeConnectorPtr props,
return false;
}
-static void for_each_active_monitor_output_wayland(gsr_egl *egl, active_monitor_callback callback, void *userdata) {
- if(!gsr_egl_supports_wayland_capture(egl))
- return;
-
+static void for_each_active_monitor_output_wayland(const gsr_egl *egl, active_monitor_callback callback, void *userdata) {
for(int i = 0; i < egl->wayland.num_outputs; ++i) {
if(!egl->wayland.outputs[i].name)
continue;
@@ -757,8 +753,8 @@ static void for_each_active_monitor_output_wayland(gsr_egl *egl, active_monitor_
}
}
-static void for_each_active_monitor_output_drm(const char *drm_card_path, active_monitor_callback callback, void *userdata) {
- int fd = open(drm_card_path, O_RDONLY);
+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)
return;
@@ -813,16 +809,16 @@ static void for_each_active_monitor_output_drm(const char *drm_card_path, active
close(fd);
}
-static void for_each_active_monitor_output(void *connection, gsr_connection_type connection_type, active_monitor_callback callback, void *userdata) {
+static void for_each_active_monitor_output(const gsr_egl *egl, gsr_connection_type connection_type, active_monitor_callback callback, void *userdata) {
switch(connection_type) {
case GSR_CONNECTION_X11:
- for_each_active_monitor_output_x11((Display*)connection, callback, userdata);
+ for_each_active_monitor_output_x11(egl->x11.dpy, callback, userdata);
break;
case GSR_CONNECTION_WAYLAND:
- for_each_active_monitor_output_wayland((gsr_egl*)connection, callback, userdata);
+ for_each_active_monitor_output_wayland(egl, callback, userdata);
break;
case GSR_CONNECTION_DRM:
- for_each_active_monitor_output_drm((const char*)connection, callback, userdata);
+ for_each_active_monitor_output_drm(egl, callback, userdata);
break;
}
}
@@ -1293,7 +1289,7 @@ static HotkeyResult replace_grabbed_keys_depending_on_active_page() {
static bool show_pkexec_flatpak_error_if_needed() {
const std::string window_str = record_area_selection_menu_get_active_id();
- if(!gsr_egl_supports_wayland_capture(&egl) && (wayland || gpu_inf.vendor != GPU_VENDOR_NVIDIA) && window_str != "window" && window_str != "focused") {
+ if((wayland || gpu_inf.vendor != GPU_VENDOR_NVIDIA) && window_str != "window" && window_str != "focused") {
if(!is_pkexec_installed()) {
GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
"pkexec needs to be installed to record a monitor with an AMD/Intel GPU. Please install and run polkit. Alternatively, record a single window which doesn't require root access.");
@@ -2153,18 +2149,11 @@ static bool audio_inputs_contains(const std::vector<AudioInput> &audio_inputs, c
return false;
}
-static void get_connection_by_active_type(void **connection, gsr_connection_type *connection_type) {
+static gsr_connection_type get_connection_type() {
if(wayland || gpu_inf.vendor != GPU_VENDOR_NVIDIA) {
- if(gsr_egl_supports_wayland_capture(&egl)) {
- *connection = &egl;
- *connection_type = GSR_CONNECTION_WAYLAND;
- } else {
- *connection = (void*)drm_card_path;
- *connection_type = GSR_CONNECTION_DRM;
- }
+ return GSR_CONNECTION_DRM;
} else {
- *connection = gdk_x11_get_default_xdisplay();
- *connection_type = GSR_CONNECTION_X11;
+ return GSR_CONNECTION_X11;
}
}
@@ -2284,7 +2273,7 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
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);
- if(is_inside_flatpak() && flatpak_is_installed_as_system() && drm_card_path[0] != '\0') {
+ if(is_inside_flatpak() && flatpak_is_installed_as_system() && egl.card_path[0] != '\0') {
GtkGrid *password_prompt_grid = GTK_GRID(gtk_grid_new());
gtk_grid_attach(grid, GTK_WIDGET(password_prompt_grid), 0, grid_row++, 2, 1);
gtk_grid_set_column_spacing(password_prompt_grid, 10);
@@ -2344,11 +2333,9 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
gtk_list_store_set(store, &iter, 1, "screen", -1);
}
- void *connection = NULL;
- gsr_connection_type connection_type = GSR_CONNECTION_DRM;
- get_connection_by_active_type(&connection, &connection_type);
+ gsr_connection_type connection_type = get_connection_type();
- for_each_active_monitor_output(connection, connection_type, [&](const gsr_monitor *monitor, void*) {
+ for_each_active_monitor_output(&egl, connection_type, [&](const gsr_monitor *monitor, void*) {
std::string label = "Monitor ";
label.append(monitor->name, monitor->name_len);
label += " (";
@@ -2356,8 +2343,7 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
label += "x";
label += std::to_string(monitor->size.y);
if(wayland) {
- if(!gsr_egl_supports_wayland_capture(&egl))
- label += ", requires root access";
+ label += ", requires root access";
} else if(gpu_inf.vendor != GPU_VENDOR_NVIDIA) {
label += ", requires root access";
}
@@ -3046,13 +3032,11 @@ static void load_config(const gpu_info &gpu_inf) {
} else if(!wayland && gpu_inf.vendor == GPU_VENDOR_NVIDIA && strcmp(config.main_config.record_area_option.c_str(), "screen") == 0) {
//
} else {
- void *connection = NULL;
- gsr_connection_type connection_type = GSR_CONNECTION_DRM;
- get_connection_by_active_type(&connection, &connection_type);
+ gsr_connection_type connection_type = get_connection_type();
bool found_monitor = false;
int monitor_name_size = strlen(config.main_config.record_area_option.c_str());
- for_each_active_monitor_output(connection, connection_type, [&](const gsr_monitor *monitor, void*) {
+ for_each_active_monitor_output(&egl, connection_type, [&](const gsr_monitor *monitor, void*) {
if(first_monitor.empty()) {
first_monitor.assign(monitor->name, monitor->name_len);
}
@@ -3265,7 +3249,7 @@ static bool is_xwayland(Display *dpy) {
return true;
bool xwayland_found = false;
- for_each_active_monitor_output(dpy, GSR_CONNECTION_X11, [&xwayland_found](const gsr_monitor *monitor, void*) {
+ for_each_active_monitor_output_x11(dpy, [&xwayland_found](const gsr_monitor *monitor, void*) {
if(monitor->name_len >= 8 && strncmp(monitor->name, "XWAYLAND", 8) == 0)
xwayland_found = true;
else if(memmem(monitor->name, monitor->name_len, "X11", 3))
@@ -3315,8 +3299,8 @@ static void activate(GtkApplication *app, gpointer) {
return;
}
- if((gpu_inf.vendor != GPU_VENDOR_NVIDIA) || (wayland && !gsr_egl_supports_wayland_capture(&egl))) {
- if(!gsr_get_valid_card_path(drm_card_path)) {
+ if((gpu_inf.vendor != GPU_VENDOR_NVIDIA) || wayland) {
+ if(!gsr_get_valid_card_path(egl.card_path)) {
GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
"Failed to find a valid DRM card.");
gtk_dialog_run(GTK_DIALOG(dialog));
@@ -3325,7 +3309,7 @@ static void activate(GtkApplication *app, gpointer) {
return;
}
} else {
- drm_card_path[0] = '\0';
+ egl.card_path[0] = '\0';
}
if(gpu_inf.vendor == GPU_VENDOR_NVIDIA) {