screencast: create gbm device

This is done by using the first device returned by getDRMDevices2
containing a render node (DRM_NODE_RENDER).
This commit is contained in:
columbarius 2021-06-22 03:07:51 +02:00
parent 7c7cb88d8f
commit 9d620273e5
4 changed files with 62 additions and 0 deletions

View file

@ -1,6 +1,7 @@
#ifndef SCREENCAST_COMMON_H
#define SCREENCAST_COMMON_H
#include <gbm.h>
#include <pipewire/pipewire.h>
#include <spa/param/video/format-utils.h>
#include <wayland-client-protocol.h>
@ -103,6 +104,9 @@ struct xdpw_screencast_context {
struct zxdg_output_manager_v1 *xdg_output_manager;
struct wl_shm *shm;
// gbm
struct gbm_device *gbm;
// sessions
struct wl_list screencast_instances;
};
@ -158,6 +162,7 @@ struct xdpw_wlr_output {
};
void randname(char *buf);
struct gbm_device *xdpw_gbm_device_create(void);
struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast,
enum buffer_type buffer_type, struct xdpw_screencopy_frame_info *frame_info);
void xdpw_buffer_destroy(struct xdpw_buffer *buffer);

View file

@ -27,6 +27,8 @@ pipewire = dependency('libpipewire-0.3', version: '>= 0.3.41')
wayland_client = dependency('wayland-client')
wayland_protos = dependency('wayland-protocols', version: '>=1.14')
iniparser = dependency('inih')
gbm = dependency('gbm')
drm = dependency('libdrm')
epoll = dependency('', required: false)
if (not cc.has_function('timerfd_create', prefix: '#include <sys/timerfd.h>') or
@ -92,6 +94,8 @@ executable(
pipewire,
rt,
iniparser,
gbm,
drm,
epoll,
],
include_directories: [inc],

View file

@ -6,6 +6,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <libdrm/drm_fourcc.h>
#include <xf86drm.h>
#include "logger.h"
@ -20,6 +21,47 @@ void randname(char *buf) {
}
}
static char *gbm_find_render_node() {
drmDevice *devices[64];
char *render_node = NULL;
int n = drmGetDevices2(0, devices, sizeof(devices) / sizeof(devices[0]));
for (int i = 0; i < n; ++i) {
drmDevice *dev = devices[i];
if (!(dev->available_nodes & (1 << DRM_NODE_RENDER)))
continue;
render_node = strdup(dev->nodes[DRM_NODE_RENDER]);
break;
}
drmFreeDevices(devices, n);
return render_node;
}
struct gbm_device *xdpw_gbm_device_create(void) {
struct gbm_device *gbm;
char *render_node = NULL;
render_node = gbm_find_render_node();
if (render_node == NULL) {
logprint(ERROR, "xdpw: Could not find render node");
return NULL;
}
logprint(INFO, "xdpw: Using render node %s", render_node);
int fd = open(render_node, O_RDWR | O_CLOEXEC);
if (fd < 0) {
logprint(ERROR, "xdpw: Could not open render node %s", render_node);
free(render_node);
return NULL;
}
free(render_node);
gbm = gbm_create_device(fd);
return gbm;
}
static int anonymous_shm_open(void) {
char name[] = "/xdpw-shm-XXXXXX";
int retries = 100;

View file

@ -641,6 +641,12 @@ int xdpw_wlr_screencopy_init(struct xdpw_state *state) {
return -1;
}
// make sure we have a gbm device
ctx->gbm = xdpw_gbm_device_create();
if (!ctx->gbm) {
logprint(ERROR, "System doesn't support gbm!");
}
return 0;
}
@ -666,6 +672,11 @@ void xdpw_wlr_screencopy_finish(struct xdpw_screencast_context *ctx) {
if (ctx->xdg_output_manager) {
zxdg_output_manager_v1_destroy(ctx->xdg_output_manager);
}
if (ctx->gbm) {
int fd = gbm_device_get_fd(ctx->gbm);
gbm_device_destroy(ctx->gbm);
close(fd);
}
if (ctx->registry) {
wl_registry_destroy(ctx->registry);
}