libweston: Get framebuffer from dma buffer in drm backend

If the client requests to take a screenshot using the writeback source
with a DMA buffer, Weston will get the framebuffer from that dmabuf
object and attach it to the writeback connector.

Original commit by Chien Phung Van.

Signed-off-by: Robert Mader <robert.mader@collabora.com>
Co-authored-by: Chien Phung Van <chien.phungvan@vn.bosch.com>
This commit is contained in:
Robert Mader 2025-09-22 17:25:39 +02:00
parent ad0f4cf94b
commit 618bfad1d4
4 changed files with 58 additions and 23 deletions

View file

@ -808,6 +808,11 @@ drm_fb_unref(struct drm_fb *fb);
struct drm_fb *
drm_fb_create_dumb(struct drm_device *device, int width, int height,
uint32_t format);
struct drm_fb *
drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
struct drm_device *device, bool is_opaque,
uint32_t *try_view_on_plane_failure_reasons);
struct drm_fb *
drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_device *device,
bool is_opaque, enum drm_fb_type type);

View file

@ -683,7 +683,7 @@ drm_output_pick_writeback_capture_task(struct drm_output *output)
struct weston_capture_task *ct;
struct weston_buffer *buffer;
struct drm_writeback *wb;
const char *msg;
char *msg;
int32_t width = output->base.current_mode->width;
int32_t height = output->base.current_mode->height;
const struct weston_drm_format_array *writeback_formats =
@ -698,14 +698,15 @@ drm_output_pick_writeback_capture_task(struct drm_output *output)
return;
if (output->base.disable_planes > 0) {
msg = "drm: KMS planes usage is disabled for now, so " \
"writeback capture tasks are rejected";
str_printf(&msg, "drm: KMS planes usage is disabled for now, " \
"so writeback capture tasks are rejected");
goto err;
}
wb = drm_output_find_compatible_writeback(output);
if (!wb) {
msg = "drm: could not find writeback connector for output";
str_printf(&msg,
"drm: could not find writeback connector for output");
goto err;
}
@ -715,14 +716,40 @@ drm_output_pick_writeback_capture_task(struct drm_output *output)
output->wb_state = drm_writeback_state_alloc();
if (!output->wb_state) {
msg = "drm: failed to allocate memory for writeback state";
str_printf(&msg,
"drm: failed to allocate memory for writeback state");
goto err;
}
output->wb_state->fb = drm_fb_create_dumb(output->device, width, height,
buffer->pixel_format->format);
if (!output->wb_state->fb) {
msg = "drm: failed to create dumb buffer for writeback state";
if (buffer->type == WESTON_BUFFER_SHM) {
output->wb_state->fb = drm_fb_create_dumb(output->device, width,
height,
buffer->pixel_format->format);
if (!output->wb_state->fb) {
str_printf(&msg,
"drm: failed to create dumb buffer for " \
"writeback state");
goto err_fb;
}
}
#ifdef BUILD_DRM_GBM
else if (buffer->type == WESTON_BUFFER_DMABUF) {
uint32_t failure_reasons = 0;
output->wb_state->fb = drm_fb_get_from_dmabuf(buffer->dmabuf,
output->device,
false,
&failure_reasons);
if (!output->wb_state->fb) {
str_printf(&msg,
"drm: failed to attach dma buffer from " \
"client for writeback state: %s",
weston_plane_failure_reasons_to_str(failure_reasons));
goto err_fb;
}
}
#endif
else {
str_printf(&msg, "drm: Invalid buffer type");
goto err_fb;
}
@ -738,6 +765,7 @@ err_fb:
output->wb_state = NULL;
err:
weston_capture_task_retire_failed(ct, msg);
free(msg);
}
#ifdef BUILD_DRM_GBM
@ -3312,20 +3340,22 @@ drm_writeback_success_screenshot(struct drm_writeback_state *state)
int dst_stride, src_stride;
uint32_t *src, *dst;
src = state->fb->map;
src_stride = state->fb->strides[0];
if (buffer->type == WESTON_BUFFER_SHM) {
src = state->fb->map;
src_stride = state->fb->strides[0];
dst = wl_shm_buffer_get_data(buffer->shm_buffer);
dst_stride = buffer->stride;
dst = wl_shm_buffer_get_data(buffer->shm_buffer);
dst_stride = buffer->stride;
width = state->fb->width;
height = state->fb->height;
width = state->fb->width;
height = state->fb->height;
wl_shm_buffer_begin_access(buffer->shm_buffer);
pixman_copy_screenshot(dst, src, dst_stride, src_stride,
buffer->pixel_format->pixman_format,
width, height);
wl_shm_buffer_end_access(buffer->shm_buffer);
wl_shm_buffer_begin_access(buffer->shm_buffer);
pixman_copy_screenshot(dst, src, dst_stride, src_stride,
buffer->pixel_format->pixman_format,
width, height);
wl_shm_buffer_end_access(buffer->shm_buffer);
}
weston_capture_task_retire_complete(state->ct);
drm_writeback_state_free(state);

View file

@ -535,7 +535,7 @@ err_free:
return NULL;
}
static struct drm_fb *
struct drm_fb *
drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
struct drm_device *device, bool is_opaque,
uint32_t *try_view_on_plane_failure_reasons)

View file

@ -171,8 +171,8 @@
image buffer. Any buffer is incompatible if it does not have
this size.
Row alignment of the buffer must be 4 bytes, and it must not contain
further row padding. Otherwise the buffer is unsupported.
For wl_shm the row alignment of the buffer must be 4 bytes, and it must
not contain further row padding. Otherwise the buffer is unsupported.
This is an initial event, and sent whenever the required size
changes.