screencast: support multiplane buffers with xdpw_buffer

This commit is contained in:
columbarius 2022-04-16 02:23:13 +02:00
parent 5799adeb57
commit 1a7276068b
4 changed files with 77 additions and 54 deletions

View file

@ -79,11 +79,12 @@ struct xdpw_buffer {
uint32_t width; uint32_t width;
uint32_t height; uint32_t height;
uint32_t format; uint32_t format;
int plane_count;
int fd; int fd[4];
uint32_t size; uint32_t size[4];
uint32_t stride; uint32_t stride[4];
uint32_t offset; uint32_t offset[4];
struct gbm_bo *bo; struct gbm_bo *bo;

View file

@ -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); wl_list_insert(&cast->buffer_list, &xdpw_buffer->link);
buffer->user_data = xdpw_buffer; buffer->user_data = xdpw_buffer;
d[0].maxsize = xdpw_buffer->size; assert(xdpw_buffer->plane_count >= 0 && buffer->buffer->n_datas == (uint32_t)xdpw_buffer->plane_count);
d[0].mapoffset = 0; for (uint32_t plane = 0; plane < buffer->buffer->n_datas; plane++) {
d[0].chunk->size = xdpw_buffer->size; d[plane].maxsize = xdpw_buffer->size[plane];
d[0].chunk->stride = xdpw_buffer->stride; d[plane].mapoffset = 0;
d[0].chunk->offset = xdpw_buffer->offset; d[plane].chunk->size = xdpw_buffer->size[plane];
d[0].flags = 0; d[plane].chunk->stride = xdpw_buffer->stride[plane];
d[0].fd = xdpw_buffer->fd; d[plane].chunk->offset = xdpw_buffer->offset[plane];
d[0].data = NULL; 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 // 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. // 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) { if (xdpw_buffer->buffer_type == DMABUF && d[plane].chunk->size == 0) {
d[0].chunk->size = 9; // This was choosen by a fair d20. 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) { if (cast->current_frame.pw_buffer == buffer) {
cast->current_frame.pw_buffer = NULL; 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; buffer->user_data = NULL;
} }
@ -300,18 +304,25 @@ void xdpw_pwr_enqueue_buffer(struct xdpw_screencast_instance *cast) {
} }
if (buffer_corrupt) { 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 { } 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, "********************");
logprint(TRACE, "pipewire: fd %u", d[0].fd); for (uint32_t plane = 0; plane < spa_buf->n_datas; plane++) {
logprint(TRACE, "pipewire: maxsize %d", d[0].maxsize); logprint(TRACE, "pipewire: plane %d", plane);
logprint(TRACE, "pipewire: size %d", d[0].chunk->size); logprint(TRACE, "pipewire: fd %u", d[plane].fd);
logprint(TRACE, "pipewire: stride %d", d[0].chunk->stride); logprint(TRACE, "pipewire: maxsize %d", d[plane].maxsize);
logprint(TRACE, "pipewire: offset %d", d[0].chunk->offset); logprint(TRACE, "pipewire: size %d", d[plane].chunk->size);
logprint(TRACE, "pipewire: chunk flags %d", d[0].chunk->flags); 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: width %d", cast->current_frame.xdpw_buffer->width);
logprint(TRACE, "pipewire: height %d", cast->current_frame.xdpw_buffer->height); logprint(TRACE, "pipewire: height %d", cast->current_frame.xdpw_buffer->height);
logprint(TRACE, "pipewire: y_invert %d", cast->current_frame.y_invert); logprint(TRACE, "pipewire: y_invert %d", cast->current_frame.y_invert);

View file

@ -110,28 +110,29 @@ struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast,
switch (buffer_type) { switch (buffer_type) {
case WL_SHM: case WL_SHM:
buffer->size = frame_info->size; buffer->plane_count = 1;
buffer->stride = frame_info->stride; buffer->size[0] = frame_info->size;
buffer->offset = 0; buffer->stride[0] = frame_info->stride;
buffer->fd = anonymous_shm_open(); buffer->offset[0] = 0;
if (buffer->fd == -1) { buffer->fd[0] = anonymous_shm_open();
if (buffer->fd[0] == -1) {
logprint(ERROR, "xdpw: unable to create anonymous filedescriptor"); logprint(ERROR, "xdpw: unable to create anonymous filedescriptor");
free(buffer); free(buffer);
return NULL; 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"); logprint(ERROR, "xdpw: unable to truncate filedescriptor");
close(buffer->fd); close(buffer->fd[0]);
free(buffer); free(buffer);
return NULL; return NULL;
} }
buffer->buffer = import_wl_shm_buffer(cast, buffer->fd, xdpw_format_wl_shm_from_drm_fourcc(frame_info->format), 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); frame_info->width, frame_info->height, frame_info->stride);
if (buffer->buffer == NULL) { if (buffer->buffer == NULL) {
logprint(ERROR, "xdpw: unable to create wl_buffer"); logprint(ERROR, "xdpw: unable to create wl_buffer");
close(buffer->fd); close(buffer->fd[0]);
free(buffer); free(buffer);
return NULL; return NULL;
} }
@ -149,6 +150,7 @@ struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast,
free(buffer); free(buffer);
return NULL; return NULL;
} }
buffer->plane_count = gbm_bo_get_plane_count(buffer->bo);
struct zwp_linux_buffer_params_v1 *params; struct zwp_linux_buffer_params_v1 *params;
params = zwp_linux_dmabuf_v1_create_params(cast->ctx->linux_dmabuf); 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; return NULL;
} }
buffer->size = 0; for (int plane = 0; plane < buffer->plane_count; plane++) {
buffer->stride = gbm_bo_get_stride(buffer->bo); buffer->size[plane] = 0;
buffer->offset = gbm_bo_get_offset(buffer->bo, 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); uint64_t mod = gbm_bo_get_modifier(buffer->bo);
buffer->fd = gbm_bo_get_fd(buffer->bo); buffer->fd[plane] = gbm_bo_get_fd_for_plane(buffer->bo, plane);
if (buffer->fd < 0) { if (buffer->fd[plane] < 0) {
logprint(ERROR, "xdpw: failed to get file descriptor"); logprint(ERROR, "xdpw: failed to get file descriptor");
zwp_linux_buffer_params_v1_destroy(params); zwp_linux_buffer_params_v1_destroy(params);
gbm_bo_destroy(buffer->bo); gbm_bo_destroy(buffer->bo);
for (int plane_tmp = 0; plane_tmp < plane; plane_tmp++) {
close(buffer->fd[plane_tmp]);
}
free(buffer); free(buffer);
return NULL; return NULL;
} }
zwp_linux_buffer_params_v1_add(params, buffer->fd, 0, buffer->offset, buffer->stride, zwp_linux_buffer_params_v1_add(params, buffer->fd[plane], plane,
mod >> 32, mod & 0xffffffff); buffer->offset[plane], buffer->stride[plane], mod >> 32, mod & 0xffffffff);
}
buffer->buffer = zwp_linux_buffer_params_v1_create_immed(params, buffer->buffer = zwp_linux_buffer_params_v1_create_immed(params,
buffer->width, buffer->height, buffer->width, buffer->height,
buffer->format, /* flags */ 0); buffer->format, /* flags */ 0);
@ -183,7 +190,9 @@ struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast,
if (!buffer->buffer) { if (!buffer->buffer) {
logprint(ERROR, "xdpw: failed to create buffer"); logprint(ERROR, "xdpw: failed to create buffer");
gbm_bo_destroy(buffer->bo); gbm_bo_destroy(buffer->bo);
close(buffer->fd); for (int plane = 0; plane < buffer->plane_count; plane++) {
close(buffer->fd[plane]);
}
free(buffer); free(buffer);
return NULL; return NULL;
} }
@ -197,7 +206,9 @@ void xdpw_buffer_destroy(struct xdpw_buffer *buffer) {
if (buffer->buffer_type == DMABUF) { if (buffer->buffer_type == DMABUF) {
gbm_bo_destroy(buffer->bo); 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); wl_list_remove(&buffer->link);
free(buffer); free(buffer);
} }

View file

@ -151,8 +151,8 @@ static void wlr_frame_buffer_done(void *data,
// Check if dequeued buffer is compatible with announced buffer // Check if dequeued buffer is compatible with announced buffer
if (( cast->buffer_type == WL_SHM && 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->size[0] != 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->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->width != cast->screencopy_frame_info[cast->buffer_type].width ||
cast->current_frame.xdpw_buffer->height != cast->screencopy_frame_info[cast->buffer_type].height) { cast->current_frame.xdpw_buffer->height != cast->screencopy_frame_info[cast->buffer_type].height) {
logprint(DEBUG, "wlroots: pipewire buffer has wrong dimensions"); logprint(DEBUG, "wlroots: pipewire buffer has wrong dimensions");