From 1a7276068b641206323fff4d587c9587ee66d2c0 Mon Sep 17 00:00:00 2001 From: columbarius Date: Sat, 16 Apr 2022 02:23:13 +0200 Subject: [PATCH] screencast: support multiplane buffers with xdpw_buffer --- include/screencast_common.h | 9 ++-- src/screencast/pipewire_screencast.c | 55 ++++++++++++++---------- src/screencast/screencast_common.c | 63 ++++++++++++++++------------ src/screencast/wlr_screencast.c | 4 +- 4 files changed, 77 insertions(+), 54 deletions(-) diff --git a/include/screencast_common.h b/include/screencast_common.h index 94cd148..8e83b6f 100644 --- a/include/screencast_common.h +++ b/include/screencast_common.h @@ -79,11 +79,12 @@ struct xdpw_buffer { uint32_t width; uint32_t height; uint32_t format; + int plane_count; - int fd; - uint32_t size; - uint32_t stride; - uint32_t offset; + int fd[4]; + uint32_t size[4]; + uint32_t stride[4]; + uint32_t offset[4]; struct gbm_bo *bo; diff --git a/src/screencast/pipewire_screencast.c b/src/screencast/pipewire_screencast.c index 1ed25b6..bec6ff6 100644 --- a/src/screencast/pipewire_screencast.c +++ b/src/screencast/pipewire_screencast.c @@ -220,19 +220,21 @@ static void pwr_handle_stream_add_buffer(void *data, struct pw_buffer *buffer) { wl_list_insert(&cast->buffer_list, &xdpw_buffer->link); buffer->user_data = xdpw_buffer; - d[0].maxsize = xdpw_buffer->size; - d[0].mapoffset = 0; - d[0].chunk->size = xdpw_buffer->size; - d[0].chunk->stride = xdpw_buffer->stride; - d[0].chunk->offset = xdpw_buffer->offset; - d[0].flags = 0; - d[0].fd = xdpw_buffer->fd; - d[0].data = NULL; - - // clients have implemented to check chunk->size if the buffer is valid instead - // of using the flags. Until they are patched we should use some arbitrary value. - if (xdpw_buffer->buffer_type == DMABUF && d[0].chunk->size == 0) { - d[0].chunk->size = 9; // This was choosen by a fair d20. + assert(xdpw_buffer->plane_count >= 0 && buffer->buffer->n_datas == (uint32_t)xdpw_buffer->plane_count); + for (uint32_t plane = 0; plane < buffer->buffer->n_datas; plane++) { + d[plane].maxsize = xdpw_buffer->size[plane]; + d[plane].mapoffset = 0; + d[plane].chunk->size = xdpw_buffer->size[plane]; + d[plane].chunk->stride = xdpw_buffer->stride[plane]; + d[plane].chunk->offset = xdpw_buffer->offset[plane]; + d[plane].flags = 0; + d[plane].fd = xdpw_buffer->fd[plane]; + d[plane].data = NULL; + // clients have implemented to check chunk->size if the buffer is valid instead + // of using the flags. Until they are patched we should use some arbitrary value. + if (xdpw_buffer->buffer_type == DMABUF && d[plane].chunk->size == 0) { + d[plane].chunk->size = 9; // This was choosen by a fair d20. + } } } @@ -248,7 +250,9 @@ static void pwr_handle_stream_remove_buffer(void *data, struct pw_buffer *buffer if (cast->current_frame.pw_buffer == buffer) { cast->current_frame.pw_buffer = NULL; } - buffer->buffer->datas[0].fd = -1; + for (uint32_t plane = 0; plane < buffer->buffer->n_datas; plane++) { + buffer->buffer->datas[plane].fd = -1; + } buffer->user_data = NULL; } @@ -300,18 +304,25 @@ void xdpw_pwr_enqueue_buffer(struct xdpw_screencast_instance *cast) { } if (buffer_corrupt) { - d[0].chunk->flags = SPA_CHUNK_FLAG_CORRUPTED; + for (uint32_t plane = 0; plane < spa_buf->n_datas; plane++) { + d[plane].chunk->flags = SPA_CHUNK_FLAG_CORRUPTED; + } } else { - d[0].chunk->flags = SPA_CHUNK_FLAG_NONE; + for (uint32_t plane = 0; plane < spa_buf->n_datas; plane++) { + d[plane].chunk->flags = SPA_CHUNK_FLAG_NONE; + } } logprint(TRACE, "********************"); - logprint(TRACE, "pipewire: fd %u", d[0].fd); - logprint(TRACE, "pipewire: maxsize %d", d[0].maxsize); - logprint(TRACE, "pipewire: size %d", d[0].chunk->size); - logprint(TRACE, "pipewire: stride %d", d[0].chunk->stride); - logprint(TRACE, "pipewire: offset %d", d[0].chunk->offset); - logprint(TRACE, "pipewire: chunk flags %d", d[0].chunk->flags); + for (uint32_t plane = 0; plane < spa_buf->n_datas; plane++) { + logprint(TRACE, "pipewire: plane %d", plane); + logprint(TRACE, "pipewire: fd %u", d[plane].fd); + logprint(TRACE, "pipewire: maxsize %d", d[plane].maxsize); + logprint(TRACE, "pipewire: size %d", d[plane].chunk->size); + logprint(TRACE, "pipewire: stride %d", d[plane].chunk->stride); + logprint(TRACE, "pipewire: offset %d", d[plane].chunk->offset); + logprint(TRACE, "pipewire: chunk flags %d", d[plane].chunk->flags); + } logprint(TRACE, "pipewire: width %d", cast->current_frame.xdpw_buffer->width); logprint(TRACE, "pipewire: height %d", cast->current_frame.xdpw_buffer->height); logprint(TRACE, "pipewire: y_invert %d", cast->current_frame.y_invert); diff --git a/src/screencast/screencast_common.c b/src/screencast/screencast_common.c index c598922..30783fe 100644 --- a/src/screencast/screencast_common.c +++ b/src/screencast/screencast_common.c @@ -110,28 +110,29 @@ struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast, switch (buffer_type) { case WL_SHM: - buffer->size = frame_info->size; - buffer->stride = frame_info->stride; - buffer->offset = 0; - buffer->fd = anonymous_shm_open(); - if (buffer->fd == -1) { + buffer->plane_count = 1; + buffer->size[0] = frame_info->size; + buffer->stride[0] = frame_info->stride; + buffer->offset[0] = 0; + buffer->fd[0] = anonymous_shm_open(); + if (buffer->fd[0] == -1) { logprint(ERROR, "xdpw: unable to create anonymous filedescriptor"); free(buffer); return NULL; } - if (ftruncate(buffer->fd, buffer->size) < 0) { + if (ftruncate(buffer->fd[0], buffer->size[0]) < 0) { logprint(ERROR, "xdpw: unable to truncate filedescriptor"); - close(buffer->fd); + close(buffer->fd[0]); free(buffer); return NULL; } - buffer->buffer = import_wl_shm_buffer(cast, buffer->fd, xdpw_format_wl_shm_from_drm_fourcc(frame_info->format), - frame_info->width, frame_info->height, frame_info->stride); + buffer->buffer = import_wl_shm_buffer(cast, buffer->fd[0], xdpw_format_wl_shm_from_drm_fourcc(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); + close(buffer->fd[0]); free(buffer); return NULL; } @@ -149,6 +150,7 @@ struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast, free(buffer); return NULL; } + buffer->plane_count = gbm_bo_get_plane_count(buffer->bo); struct zwp_linux_buffer_params_v1 *params; params = zwp_linux_dmabuf_v1_create_params(cast->ctx->linux_dmabuf); @@ -159,22 +161,27 @@ struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast, return NULL; } - buffer->size = 0; - buffer->stride = gbm_bo_get_stride(buffer->bo); - buffer->offset = gbm_bo_get_offset(buffer->bo, 0); - uint64_t mod = gbm_bo_get_modifier(buffer->bo); - buffer->fd = gbm_bo_get_fd(buffer->bo); + for (int plane = 0; plane < buffer->plane_count; plane++) { + buffer->size[plane] = 0; + buffer->stride[plane] = gbm_bo_get_stride_for_plane(buffer->bo, plane); + buffer->offset[plane] = gbm_bo_get_offset(buffer->bo, plane); + uint64_t mod = gbm_bo_get_modifier(buffer->bo); + buffer->fd[plane] = gbm_bo_get_fd_for_plane(buffer->bo, plane); - if (buffer->fd < 0) { - logprint(ERROR, "xdpw: failed to get file descriptor"); - zwp_linux_buffer_params_v1_destroy(params); - gbm_bo_destroy(buffer->bo); - free(buffer); - return NULL; + if (buffer->fd[plane] < 0) { + logprint(ERROR, "xdpw: failed to get file descriptor"); + zwp_linux_buffer_params_v1_destroy(params); + gbm_bo_destroy(buffer->bo); + for (int plane_tmp = 0; plane_tmp < plane; plane_tmp++) { + close(buffer->fd[plane_tmp]); + } + free(buffer); + return NULL; + } + + zwp_linux_buffer_params_v1_add(params, buffer->fd[plane], plane, + buffer->offset[plane], buffer->stride[plane], mod >> 32, mod & 0xffffffff); } - - zwp_linux_buffer_params_v1_add(params, buffer->fd, 0, buffer->offset, buffer->stride, - mod >> 32, mod & 0xffffffff); buffer->buffer = zwp_linux_buffer_params_v1_create_immed(params, buffer->width, buffer->height, buffer->format, /* flags */ 0); @@ -183,7 +190,9 @@ struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast, if (!buffer->buffer) { logprint(ERROR, "xdpw: failed to create buffer"); gbm_bo_destroy(buffer->bo); - close(buffer->fd); + for (int plane = 0; plane < buffer->plane_count; plane++) { + close(buffer->fd[plane]); + } free(buffer); return NULL; } @@ -197,7 +206,9 @@ void xdpw_buffer_destroy(struct xdpw_buffer *buffer) { if (buffer->buffer_type == DMABUF) { gbm_bo_destroy(buffer->bo); } - close(buffer->fd); + for (int plane = 0; plane < buffer->plane_count; plane++) { + close(buffer->fd[plane]); + } wl_list_remove(&buffer->link); free(buffer); } diff --git a/src/screencast/wlr_screencast.c b/src/screencast/wlr_screencast.c index 70d391e..5c4b1e4 100644 --- a/src/screencast/wlr_screencast.c +++ b/src/screencast/wlr_screencast.c @@ -151,8 +151,8 @@ static void wlr_frame_buffer_done(void *data, // Check if dequeued buffer is compatible with announced buffer if (( cast->buffer_type == WL_SHM && - (cast->current_frame.xdpw_buffer->size != cast->screencopy_frame_info[cast->buffer_type].size || - cast->current_frame.xdpw_buffer->stride != cast->screencopy_frame_info[cast->buffer_type].stride)) || + (cast->current_frame.xdpw_buffer->size[0] != cast->screencopy_frame_info[cast->buffer_type].size || + cast->current_frame.xdpw_buffer->stride[0] != cast->screencopy_frame_info[cast->buffer_type].stride)) || cast->current_frame.xdpw_buffer->width != cast->screencopy_frame_info[cast->buffer_type].width || cast->current_frame.xdpw_buffer->height != cast->screencopy_frame_info[cast->buffer_type].height) { logprint(DEBUG, "wlroots: pipewire buffer has wrong dimensions");