diff --git a/include/wlr/types/wlr_linux_dmabuf_v1.h b/include/wlr/types/wlr_linux_dmabuf_v1.h index 94fffe98..6bb0712e 100644 --- a/include/wlr/types/wlr_linux_dmabuf_v1.h +++ b/include/wlr/types/wlr_linux_dmabuf_v1.h @@ -111,4 +111,19 @@ struct wlr_linux_dmabuf_feedback_v1_tranche *wlr_linux_dmabuf_feedback_add_tranc */ void wlr_linux_dmabuf_feedback_v1_finish(struct wlr_linux_dmabuf_feedback_v1 *feedback); +struct wlr_linux_dmabuf_feedback_v1_init_options { + // Main renderer used by the compositor + struct wlr_renderer *main_renderer; + // Output on which direct scan-out is possible on the primary plane, or NULL + struct wlr_output *scanout_primary_output; +}; + +/** + * Initialize a DMA-BUF feedback object with the provided options. + * + * The caller is responsible for calling wlr_linux_dmabuf_feedback_v1_finish() after use. + */ +bool wlr_linux_dmabuf_feedback_v1_init_with_options(struct wlr_linux_dmabuf_feedback_v1 *feedback, + const struct wlr_linux_dmabuf_feedback_v1_init_options *options); + #endif diff --git a/types/wlr_linux_dmabuf_v1.c b/types/wlr_linux_dmabuf_v1.c index 07f62909..8098be22 100644 --- a/types/wlr_linux_dmabuf_v1.c +++ b/types/wlr_linux_dmabuf_v1.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -1076,3 +1077,87 @@ void wlr_linux_dmabuf_feedback_v1_finish(struct wlr_linux_dmabuf_feedback_v1 *fe } wl_array_release(&feedback->tranches); } + +static bool devid_from_fd(int fd, dev_t *devid) { + struct stat stat; + if (fstat(fd, &stat) != 0) { + wlr_log_errno(WLR_ERROR, "fstat failed"); + return false; + } + *devid = stat.st_rdev; + return true; +} + +bool wlr_linux_dmabuf_feedback_v1_init_with_options(struct wlr_linux_dmabuf_feedback_v1 *feedback, + const struct wlr_linux_dmabuf_feedback_v1_init_options *options) { + assert(options->main_renderer != NULL); + + memset(feedback, 0, sizeof(*feedback)); + + int renderer_drm_fd = wlr_renderer_get_drm_fd(options->main_renderer); + if (renderer_drm_fd < 0) { + wlr_log(WLR_ERROR, "Failed to get renderer DRM FD"); + goto error; + } + dev_t renderer_dev; + if (!devid_from_fd(renderer_drm_fd, &renderer_dev)) { + goto error; + } + + feedback->main_device = renderer_dev; + + const struct wlr_drm_format_set *renderer_formats = + wlr_renderer_get_dmabuf_texture_formats(options->main_renderer); + if (renderer_formats == NULL) { + wlr_log(WLR_ERROR, "Failed to get renderer DMA-BUF texture formats"); + goto error; + } + + if (options->scanout_primary_output != NULL) { + int backend_drm_fd = wlr_backend_get_drm_fd(options->scanout_primary_output->backend); + if (backend_drm_fd < 0) { + wlr_log(WLR_ERROR, "Failed to get backend DRM FD"); + goto error; + } + dev_t backend_dev; + if (!devid_from_fd(backend_drm_fd, &backend_dev)) { + goto error; + } + + const struct wlr_drm_format_set *scanout_formats = + wlr_output_get_primary_formats(options->scanout_primary_output, WLR_BUFFER_CAP_DMABUF); + if (scanout_formats == NULL) { + wlr_log(WLR_ERROR, "Failed to get output primary DMA-BUF formats"); + goto error; + } + + struct wlr_linux_dmabuf_feedback_v1_tranche *tranche = + wlr_linux_dmabuf_feedback_add_tranche(feedback); + if (tranche == NULL) { + goto error; + } + + tranche->target_device = backend_dev; + if (!wlr_drm_format_set_intersect(&tranche->formats, scanout_formats, renderer_formats)) { + wlr_log(WLR_ERROR, "Failed to intersect renderer and scanout formats"); + goto error; + } + } + + struct wlr_linux_dmabuf_feedback_v1_tranche *tranche = + wlr_linux_dmabuf_feedback_add_tranche(feedback); + if (tranche == NULL) { + goto error; + } + + tranche->target_device = renderer_dev; + if (!wlr_drm_format_set_copy(&tranche->formats, renderer_formats)) { + goto error; + } + + return true; + +error: + wlr_linux_dmabuf_feedback_v1_finish(feedback); + return false; +}