mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2024-11-27 00:15:59 +01:00
058bd97815
It showed that handling self contained buffers is much easier then have the metadata of the buffer seperated from the actual buffer attached to the screencast instance. The goal of the following changes is to separate the meta informations like requested buffer attributes and wlr_screencast data from the actual buffers. This enables us to: * Simplify the flow between the PipeWire loop and the wlroots one * Track and apply damage to each used buffer (ext_screencopy)
193 lines
5.2 KiB
C
193 lines
5.2 KiB
C
#include "screencast_common.h"
|
|
#include <assert.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include "logger.h"
|
|
|
|
void randname(char *buf) {
|
|
struct timespec ts;
|
|
clock_gettime(CLOCK_REALTIME, &ts);
|
|
long r = ts.tv_nsec;
|
|
for (int i = 0; i < 6; ++i) {
|
|
assert(buf[i] == 'X');
|
|
buf[i] = 'A'+(r&15)+(r&16)*2;
|
|
r >>= 5;
|
|
}
|
|
}
|
|
|
|
static int anonymous_shm_open(void) {
|
|
char name[] = "/xdpw-shm-XXXXXX";
|
|
int retries = 100;
|
|
|
|
do {
|
|
randname(name + strlen(name) - 6);
|
|
|
|
--retries;
|
|
// shm_open guarantees that O_CLOEXEC is set
|
|
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
|
if (fd >= 0) {
|
|
shm_unlink(name);
|
|
return fd;
|
|
}
|
|
} while (retries > 0 && errno == EEXIST);
|
|
|
|
return -1;
|
|
}
|
|
|
|
static struct wl_buffer *import_wl_shm_buffer(struct xdpw_screencast_instance *cast, int fd,
|
|
enum wl_shm_format fmt, int width, int height, int stride) {
|
|
struct xdpw_screencast_context *ctx = cast->ctx;
|
|
int size = stride * height;
|
|
|
|
if (fd < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
struct wl_shm_pool *pool = wl_shm_create_pool(ctx->shm, fd, size);
|
|
struct wl_buffer *buffer =
|
|
wl_shm_pool_create_buffer(pool, 0, width, height, stride, fmt);
|
|
wl_shm_pool_destroy(pool);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast,
|
|
struct xdpw_screencopy_frame_info *frame_info) {
|
|
struct xdpw_buffer *buffer = calloc(1, sizeof(struct xdpw_buffer));
|
|
buffer->width = frame_info->width;
|
|
buffer->height = frame_info->height;
|
|
buffer->format = frame_info->format;
|
|
buffer->size = frame_info->size;
|
|
buffer->stride = frame_info->stride;
|
|
buffer->offset = 0;
|
|
buffer->fd = anonymous_shm_open();
|
|
if (buffer->fd == -1) {
|
|
logprint(ERROR, "xdpw: unable to create anonymous filedescriptor");
|
|
free(buffer);
|
|
return NULL;
|
|
}
|
|
|
|
if (ftruncate(buffer->fd, buffer->size) < 0) {
|
|
logprint(ERROR, "xdpw: unable to truncate filedescriptor");
|
|
close(buffer->fd);
|
|
free(buffer);
|
|
return NULL;
|
|
}
|
|
|
|
buffer->buffer = import_wl_shm_buffer(cast, buffer->fd, frame_info->format,
|
|
frame_info->width, frame_info->height, frame_info->stride);
|
|
if (buffer->buffer == NULL) {
|
|
logprint(ERROR, "xdpw: unable to create wl_buffer");
|
|
close(buffer->fd);
|
|
free(buffer);
|
|
return NULL;
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
void xdpw_buffer_destroy(struct xdpw_buffer *buffer) {
|
|
wl_buffer_destroy(buffer->buffer);
|
|
close(buffer->fd);
|
|
wl_list_remove(&buffer->link);
|
|
free(buffer);
|
|
}
|
|
|
|
enum spa_video_format xdpw_format_pw_from_wl_shm(enum wl_shm_format format) {
|
|
switch (format) {
|
|
case WL_SHM_FORMAT_ARGB8888:
|
|
return SPA_VIDEO_FORMAT_BGRA;
|
|
case WL_SHM_FORMAT_XRGB8888:
|
|
return SPA_VIDEO_FORMAT_BGRx;
|
|
case WL_SHM_FORMAT_RGBA8888:
|
|
return SPA_VIDEO_FORMAT_ABGR;
|
|
case WL_SHM_FORMAT_RGBX8888:
|
|
return SPA_VIDEO_FORMAT_xBGR;
|
|
case WL_SHM_FORMAT_ABGR8888:
|
|
return SPA_VIDEO_FORMAT_RGBA;
|
|
case WL_SHM_FORMAT_XBGR8888:
|
|
return SPA_VIDEO_FORMAT_RGBx;
|
|
case WL_SHM_FORMAT_BGRA8888:
|
|
return SPA_VIDEO_FORMAT_ARGB;
|
|
case WL_SHM_FORMAT_BGRX8888:
|
|
return SPA_VIDEO_FORMAT_xRGB;
|
|
case WL_SHM_FORMAT_NV12:
|
|
return SPA_VIDEO_FORMAT_NV12;
|
|
case WL_SHM_FORMAT_XRGB2101010:
|
|
return SPA_VIDEO_FORMAT_xRGB_210LE;
|
|
case WL_SHM_FORMAT_XBGR2101010:
|
|
return SPA_VIDEO_FORMAT_xBGR_210LE;
|
|
case WL_SHM_FORMAT_RGBX1010102:
|
|
return SPA_VIDEO_FORMAT_RGBx_102LE;
|
|
case WL_SHM_FORMAT_BGRX1010102:
|
|
return SPA_VIDEO_FORMAT_BGRx_102LE;
|
|
case WL_SHM_FORMAT_ARGB2101010:
|
|
return SPA_VIDEO_FORMAT_ARGB_210LE;
|
|
case WL_SHM_FORMAT_ABGR2101010:
|
|
return SPA_VIDEO_FORMAT_ABGR_210LE;
|
|
case WL_SHM_FORMAT_RGBA1010102:
|
|
return SPA_VIDEO_FORMAT_RGBA_102LE;
|
|
case WL_SHM_FORMAT_BGRA1010102:
|
|
return SPA_VIDEO_FORMAT_BGRA_102LE;
|
|
default:
|
|
logprint(ERROR, "xdg-desktop-portal-wlr: failed to convert wl_shm "
|
|
"format 0x%08x to spa_video_format", format);
|
|
abort();
|
|
}
|
|
}
|
|
|
|
enum spa_video_format xdpw_format_pw_strip_alpha(enum spa_video_format format) {
|
|
switch (format) {
|
|
case SPA_VIDEO_FORMAT_BGRA:
|
|
return SPA_VIDEO_FORMAT_BGRx;
|
|
case SPA_VIDEO_FORMAT_ABGR:
|
|
return SPA_VIDEO_FORMAT_xBGR;
|
|
case SPA_VIDEO_FORMAT_RGBA:
|
|
return SPA_VIDEO_FORMAT_RGBx;
|
|
case SPA_VIDEO_FORMAT_ARGB:
|
|
return SPA_VIDEO_FORMAT_xRGB;
|
|
case SPA_VIDEO_FORMAT_ARGB_210LE:
|
|
return SPA_VIDEO_FORMAT_xRGB_210LE;
|
|
case SPA_VIDEO_FORMAT_ABGR_210LE:
|
|
return SPA_VIDEO_FORMAT_xBGR_210LE;
|
|
case SPA_VIDEO_FORMAT_RGBA_102LE:
|
|
return SPA_VIDEO_FORMAT_RGBx_102LE;
|
|
case SPA_VIDEO_FORMAT_BGRA_102LE:
|
|
return SPA_VIDEO_FORMAT_BGRx_102LE;
|
|
default:
|
|
return SPA_VIDEO_FORMAT_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
enum xdpw_chooser_types get_chooser_type(const char *chooser_type) {
|
|
if (!chooser_type || strcmp(chooser_type, "default") == 0) {
|
|
return XDPW_CHOOSER_DEFAULT;
|
|
} else if (strcmp(chooser_type, "none") == 0) {
|
|
return XDPW_CHOOSER_NONE;
|
|
} else if (strcmp(chooser_type, "simple") == 0) {
|
|
return XDPW_CHOOSER_SIMPLE;
|
|
} else if (strcmp(chooser_type, "dmenu") == 0) {
|
|
return XDPW_CHOOSER_DMENU;
|
|
}
|
|
fprintf(stderr, "Could not understand chooser type %s\n", chooser_type);
|
|
exit(1);
|
|
}
|
|
|
|
const char *chooser_type_str(enum xdpw_chooser_types chooser_type) {
|
|
switch (chooser_type) {
|
|
case XDPW_CHOOSER_DEFAULT:
|
|
return "default";
|
|
case XDPW_CHOOSER_NONE:
|
|
return "none";
|
|
case XDPW_CHOOSER_SIMPLE:
|
|
return "simple";
|
|
case XDPW_CHOOSER_DMENU:
|
|
return "dmenu";
|
|
}
|
|
fprintf(stderr, "Could not find chooser type %d\n", chooser_type);
|
|
abort();
|
|
}
|