mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-13 08:22:16 -04:00
Merge branch 'capture_sync_2' into 'master'
Draft: ext_image_capture_source_v1: wait for explicit sync Closes #4064 See merge request wlroots/wlroots!5314
This commit is contained in:
commit
5ad5818bec
8 changed files with 175 additions and 20 deletions
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
struct wlr_buffer;
|
||||
|
||||
/**
|
||||
* Accumulate timeline points, to have a destination timeline point be
|
||||
* signalled when all inputs are
|
||||
|
|
@ -41,4 +43,22 @@ bool wlr_drm_syncobj_merger_add(struct wlr_drm_syncobj_merger *merger,
|
|||
struct wlr_drm_syncobj_timeline *dst_timeline, uint64_t dst_point,
|
||||
struct wl_event_loop *loop);
|
||||
|
||||
/**
|
||||
* Add a new sync file to wait for.
|
||||
*
|
||||
* Ownership of fd is transferred to the merger.
|
||||
*/
|
||||
bool wlr_drm_syncobj_merger_add_sync_file(struct wlr_drm_syncobj_merger *merger,
|
||||
int fd);
|
||||
|
||||
/**
|
||||
* Add a new DMA-BUF release to wait for.
|
||||
*
|
||||
* Waits for write access.
|
||||
* If the platform does not support DMA-BUF<->sync file interop, the supplied
|
||||
* event_loop is used to schedule a wait.
|
||||
*/
|
||||
bool wlr_drm_syncobj_merger_add_dmabuf(struct wlr_drm_syncobj_merger *merger,
|
||||
struct wlr_buffer *buffer, struct wl_event_loop *event_loop);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include <time.h>
|
||||
|
||||
struct wlr_renderer;
|
||||
struct wlr_drm_syncobj_timeline;
|
||||
|
||||
struct wlr_ext_image_copy_capture_manager_v1 {
|
||||
struct wl_global *global;
|
||||
|
|
@ -82,6 +83,7 @@ void wlr_ext_image_copy_capture_frame_v1_fail(struct wlr_ext_image_copy_capture_
|
|||
* Copy a struct wlr_buffer into the client-provided buffer for the frame.
|
||||
*/
|
||||
bool wlr_ext_image_copy_capture_frame_v1_copy_buffer(struct wlr_ext_image_copy_capture_frame_v1 *frame,
|
||||
struct wlr_buffer *src, struct wlr_renderer *renderer);
|
||||
struct wlr_buffer *src, struct wlr_renderer *renderer,
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -74,4 +74,21 @@ bool wlr_linux_drm_syncobj_v1_state_add_release_point(
|
|||
struct wlr_drm_syncobj_timeline *release_timeline, uint64_t release_point,
|
||||
struct wl_event_loop *event_loop);
|
||||
|
||||
/**
|
||||
* Register the DMA-BUF release of a buffer for buffer usage.
|
||||
* Non-dmabuf buffers are considered to be immediately available (no wait).
|
||||
*
|
||||
* This function may be called multiple times for the same commit. The client's
|
||||
* release point will be signalled when all registered points are signalled, and
|
||||
* a new buffer has been committed.
|
||||
*
|
||||
* Because the platform may not support DMA-BUF fence merges, a wl_event_loop
|
||||
* must be supplied to schedule a wait internally, if needed
|
||||
*
|
||||
* Waits for write access
|
||||
*/
|
||||
bool wlr_linux_drm_syncobj_v1_state_add_release_from_implicit_sync(
|
||||
struct wlr_linux_drm_syncobj_surface_v1_state *state,
|
||||
struct wlr_buffer *buffer, struct wl_event_loop *event_loop);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
#include <unistd.h>
|
||||
#include <wayland-util.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <xf86drm.h>
|
||||
#include "render/dmabuf.h"
|
||||
#include "render/drm_syncobj_merger.h"
|
||||
|
||||
#include "config.h"
|
||||
|
|
@ -79,14 +81,7 @@ void wlr_drm_syncobj_merger_unref(struct wlr_drm_syncobj_merger *merger) {
|
|||
static bool merger_add_exportable(struct wlr_drm_syncobj_merger *merger,
|
||||
struct wlr_drm_syncobj_timeline *src_timeline, uint64_t src_point) {
|
||||
int new_sync = wlr_drm_syncobj_timeline_export_sync_file(src_timeline, src_point);
|
||||
if (merger->sync_fd != -1) {
|
||||
int fd2 = new_sync;
|
||||
new_sync = sync_file_merge(merger->sync_fd, fd2);
|
||||
close(fd2);
|
||||
close(merger->sync_fd);
|
||||
}
|
||||
merger->sync_fd = new_sync;
|
||||
return true;
|
||||
return wlr_drm_syncobj_merger_add_sync_file(merger, new_sync);
|
||||
}
|
||||
|
||||
struct export_waiter {
|
||||
|
|
@ -131,3 +126,69 @@ bool wlr_drm_syncobj_merger_add(struct wlr_drm_syncobj_merger *merger,
|
|||
merger->n_ref++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wlr_drm_syncobj_merger_add_sync_file(struct wlr_drm_syncobj_merger *merger,
|
||||
int fd) {
|
||||
int new_sync = fd;
|
||||
if (merger->sync_fd != -1) {
|
||||
new_sync = sync_file_merge(merger->sync_fd, fd);
|
||||
close(fd);
|
||||
close(merger->sync_fd);
|
||||
}
|
||||
merger->sync_fd = new_sync;
|
||||
return merger->sync_fd != -1;
|
||||
}
|
||||
|
||||
struct poll_waiter {
|
||||
struct wl_event_source *event_source;
|
||||
struct wlr_drm_syncobj_merger *merger;
|
||||
};
|
||||
|
||||
static int poll_waiter_handle_done(int fd, uint32_t mask, void *data) {
|
||||
struct poll_waiter *waiter = data;
|
||||
wlr_drm_syncobj_merger_unref(waiter->merger);
|
||||
wl_event_source_remove(waiter->event_source);
|
||||
free(waiter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool wlr_drm_syncobj_merger_add_dmabuf(struct wlr_drm_syncobj_merger *merger,
|
||||
struct wlr_buffer *buffer, struct wl_event_loop *event_loop) {
|
||||
struct wlr_dmabuf_attributes dmabuf_attributes;
|
||||
if (!wlr_buffer_get_dmabuf(buffer, &dmabuf_attributes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool res = true;
|
||||
for (int i = 0; i < dmabuf_attributes.n_planes; ++i) {
|
||||
int sync_fd = dmabuf_export_sync_file(dmabuf_attributes.fd[i], DMA_BUF_SYNC_WRITE);
|
||||
if (sync_fd == -1) {
|
||||
res = false;
|
||||
break;
|
||||
}
|
||||
if (!wlr_drm_syncobj_merger_add_sync_file(merger, sync_fd)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (res) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t mask = WL_EVENT_ERROR | WL_EVENT_HANGUP | WL_EVENT_WRITABLE;
|
||||
for (int i = 0; i < dmabuf_attributes.n_planes; ++i) {
|
||||
struct poll_waiter *waiter = calloc(1, sizeof(*waiter));
|
||||
if (waiter == NULL) {
|
||||
return false;
|
||||
}
|
||||
waiter->merger = wlr_drm_syncobj_merger_ref(merger);
|
||||
waiter->event_source = wl_event_loop_add_fd(event_loop,
|
||||
dmabuf_attributes.fd[i], mask, poll_waiter_handle_done, waiter);
|
||||
if (waiter->event_source == NULL) {
|
||||
wlr_drm_syncobj_merger_unref(waiter->merger);
|
||||
free(waiter);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ struct wlr_ext_output_image_capture_source_v1_frame_event {
|
|||
struct wlr_ext_image_capture_source_v1_frame_event base;
|
||||
struct wlr_buffer *buffer;
|
||||
struct timespec when;
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||
uint64_t wait_point;
|
||||
};
|
||||
|
||||
static void output_source_start(struct wlr_ext_image_capture_source_v1 *base,
|
||||
|
|
@ -86,7 +88,8 @@ static void output_source_copy_frame(struct wlr_ext_image_capture_source_v1 *bas
|
|||
wl_container_of(base_event, event, base);
|
||||
|
||||
if (wlr_ext_image_copy_capture_frame_v1_copy_buffer(frame,
|
||||
event->buffer, source->output->renderer)) {
|
||||
event->buffer, source->output->renderer,
|
||||
event->wait_timeline, event->wait_point)) {
|
||||
wlr_ext_image_copy_capture_frame_v1_ready(frame,
|
||||
source->output->transform, &event->when);
|
||||
}
|
||||
|
|
@ -152,6 +155,10 @@ static void source_handle_output_commit(struct wl_listener *listener,
|
|||
.buffer = buffer,
|
||||
.when = event->when, // TODO: predict next presentation time instead
|
||||
};
|
||||
if (event->state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
|
||||
frame_event.wait_timeline = event->state->wait_timeline;
|
||||
frame_event.wait_point = event->state->wait_point;
|
||||
}
|
||||
wl_signal_emit_mutable(&source->base.events.frame, &frame_event);
|
||||
|
||||
pixman_region32_fini(&full_damage);
|
||||
|
|
@ -279,6 +286,8 @@ static void output_cursor_source_copy_frame(struct wlr_ext_image_capture_source_
|
|||
struct wlr_ext_image_copy_capture_frame_v1 *frame,
|
||||
struct wlr_ext_image_capture_source_v1_frame_event *base_event) {
|
||||
struct output_cursor_source *cursor_source = wl_container_of(base, cursor_source, base);
|
||||
struct wlr_ext_output_image_capture_source_v1_frame_event *event =
|
||||
wl_container_of(base_event, event, base);
|
||||
|
||||
struct wlr_buffer *src_buffer = cursor_source->output->cursor_front_buffer;
|
||||
if (src_buffer == NULL) {
|
||||
|
|
@ -287,7 +296,8 @@ static void output_cursor_source_copy_frame(struct wlr_ext_image_capture_source_
|
|||
}
|
||||
|
||||
if (!wlr_ext_image_copy_capture_frame_v1_copy_buffer(frame,
|
||||
src_buffer, cursor_source->output->renderer)) {
|
||||
src_buffer, cursor_source->output->renderer,
|
||||
event->wait_timeline, event->wait_point)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include "render/dmabuf.h"
|
||||
#include "render/drm_syncobj_merger.h"
|
||||
#include "types/wlr_output.h"
|
||||
#include "types/wlr_scene.h"
|
||||
|
||||
|
|
@ -30,6 +32,9 @@ struct scene_node_source_frame_event {
|
|||
struct wlr_ext_image_capture_source_v1_frame_event base;
|
||||
struct wlr_buffer *buffer;
|
||||
struct timespec when;
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||
uint64_t wait_point;
|
||||
struct wlr_drm_syncobj_merger *release_merger;
|
||||
};
|
||||
|
||||
static size_t last_output_num = 0;
|
||||
|
|
@ -149,9 +154,14 @@ static void source_copy_frame(struct wlr_ext_image_capture_source_v1 *base,
|
|||
struct scene_node_source_frame_event *event = wl_container_of(base_event, event, base);
|
||||
|
||||
if (wlr_ext_image_copy_capture_frame_v1_copy_buffer(frame,
|
||||
event->buffer, source->output.renderer)) {
|
||||
event->buffer, source->output.renderer,
|
||||
event->wait_timeline, event->wait_point)) {
|
||||
wlr_ext_image_copy_capture_frame_v1_ready(frame,
|
||||
source->output.transform, &event->when);
|
||||
if (event->release_merger) {
|
||||
wlr_drm_syncobj_merger_add_dmabuf(event->release_merger, frame->buffer,
|
||||
source->output.event_loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +172,14 @@ static const struct wlr_ext_image_capture_source_v1_interface source_impl = {
|
|||
.copy_frame = source_copy_frame,
|
||||
};
|
||||
|
||||
static const struct wlr_backend_impl backend_impl = {0};
|
||||
static int source_backend_get_drm_fd(struct wlr_backend *backend) {
|
||||
struct scene_node_source *source = wl_container_of(backend, source, backend);
|
||||
return wlr_renderer_get_drm_fd(source->output.renderer);
|
||||
}
|
||||
|
||||
static const struct wlr_backend_impl backend_impl = {
|
||||
.get_drm_fd = source_backend_get_drm_fd
|
||||
};
|
||||
|
||||
static void source_update_buffer_constraints(struct scene_node_source *source,
|
||||
const struct wlr_output_state *state) {
|
||||
|
|
@ -180,6 +197,8 @@ static bool output_test(struct wlr_output *output, const struct wlr_output_state
|
|||
uint32_t supported =
|
||||
WLR_OUTPUT_STATE_BACKEND_OPTIONAL |
|
||||
WLR_OUTPUT_STATE_BUFFER |
|
||||
WLR_OUTPUT_STATE_WAIT_TIMELINE |
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
|
||||
WLR_OUTPUT_STATE_ENABLED |
|
||||
WLR_OUTPUT_STATE_MODE;
|
||||
if ((state->committed & ~supported) != 0) {
|
||||
|
|
@ -242,7 +261,16 @@ static bool output_commit(struct wlr_output *output, const struct wlr_output_sta
|
|||
.buffer = buffer,
|
||||
.when = now,
|
||||
};
|
||||
if (state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
|
||||
frame_event.wait_timeline = state->wait_timeline;
|
||||
frame_event.wait_point = state->wait_point;
|
||||
}
|
||||
if (state->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
|
||||
frame_event.release_merger = wlr_drm_syncobj_merger_create(
|
||||
state->signal_timeline, state->signal_point);
|
||||
}
|
||||
wl_signal_emit_mutable(&source->base.events.frame, &frame_event.base);
|
||||
wlr_drm_syncobj_merger_unref(frame_event.release_merger);
|
||||
|
||||
pixman_region32_fini(&full_damage);
|
||||
|
||||
|
|
@ -311,6 +339,7 @@ struct wlr_ext_image_capture_source_v1 *wlr_ext_image_capture_source_v1_create_w
|
|||
|
||||
wlr_backend_init(&source->backend, &backend_impl);
|
||||
source->backend.buffer_caps = WLR_BUFFER_CAP_DMABUF | WLR_BUFFER_CAP_SHM;
|
||||
source->backend.features.timeline = true;
|
||||
|
||||
wlr_output_init(&source->output, &source->backend, &output_impl, event_loop, NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -105,9 +105,9 @@ void wlr_ext_image_copy_capture_frame_v1_ready(struct wlr_ext_image_copy_capture
|
|||
frame_destroy(frame);
|
||||
}
|
||||
|
||||
static bool copy_dmabuf(struct wlr_buffer *dst,
|
||||
struct wlr_buffer *src, struct wlr_renderer *renderer,
|
||||
const pixman_region32_t *clip) {
|
||||
static bool copy_dmabuf(struct wlr_buffer *dst, struct wlr_buffer *src,
|
||||
struct wlr_renderer *renderer, const pixman_region32_t *clip,
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point) {
|
||||
struct wlr_texture *texture = wlr_texture_from_buffer(renderer, src);
|
||||
if (texture == NULL) {
|
||||
return false;
|
||||
|
|
@ -123,6 +123,8 @@ static bool copy_dmabuf(struct wlr_buffer *dst,
|
|||
.texture = texture,
|
||||
.clip = clip,
|
||||
.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
|
||||
.wait_timeline = wait_timeline,
|
||||
.wait_point = wait_point,
|
||||
});
|
||||
|
||||
ok = wlr_render_pass_submit(pass);
|
||||
|
|
@ -133,7 +135,8 @@ out:
|
|||
}
|
||||
|
||||
static bool copy_shm(void *data, uint32_t format, size_t stride,
|
||||
struct wlr_buffer *src, struct wlr_renderer *renderer) {
|
||||
struct wlr_buffer *src, struct wlr_renderer *renderer,
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point) {
|
||||
// TODO: bypass renderer if source buffer supports data ptr access
|
||||
struct wlr_texture *texture = wlr_texture_from_buffer(renderer, src);
|
||||
if (!texture) {
|
||||
|
|
@ -145,6 +148,8 @@ static bool copy_shm(void *data, uint32_t format, size_t stride,
|
|||
.data = data,
|
||||
.format = format,
|
||||
.stride = stride,
|
||||
.wait_timeline = wait_timeline,
|
||||
.wait_point = wait_point,
|
||||
});
|
||||
|
||||
wlr_texture_destroy(texture);
|
||||
|
|
@ -153,7 +158,8 @@ static bool copy_shm(void *data, uint32_t format, size_t stride,
|
|||
}
|
||||
|
||||
bool wlr_ext_image_copy_capture_frame_v1_copy_buffer(struct wlr_ext_image_copy_capture_frame_v1 *frame,
|
||||
struct wlr_buffer *src, struct wlr_renderer *renderer) {
|
||||
struct wlr_buffer *src, struct wlr_renderer *renderer,
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point) {
|
||||
struct wlr_buffer *dst = frame->buffer;
|
||||
|
||||
if (src->width != dst->width || src->height != dst->height) {
|
||||
|
|
@ -174,7 +180,7 @@ bool wlr_ext_image_copy_capture_frame_v1_copy_buffer(struct wlr_ext_image_copy_c
|
|||
ok = false;
|
||||
failure_reason = EXT_IMAGE_COPY_CAPTURE_FRAME_V1_FAILURE_REASON_BUFFER_CONSTRAINTS;
|
||||
} else {
|
||||
ok = copy_dmabuf(dst, src, renderer, &frame->buffer_damage);
|
||||
ok = copy_dmabuf(dst, src, renderer, &frame->buffer_damage, wait_timeline, wait_point);
|
||||
}
|
||||
} else if (wlr_buffer_begin_data_ptr_access(dst,
|
||||
WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride)) {
|
||||
|
|
@ -182,7 +188,7 @@ bool wlr_ext_image_copy_capture_frame_v1_copy_buffer(struct wlr_ext_image_copy_c
|
|||
ok = false;
|
||||
failure_reason = EXT_IMAGE_COPY_CAPTURE_FRAME_V1_FAILURE_REASON_BUFFER_CONSTRAINTS;
|
||||
} else {
|
||||
ok = copy_shm(data, format, stride, src, renderer);
|
||||
ok = copy_shm(data, format, stride, src, renderer, wait_timeline, wait_point);
|
||||
}
|
||||
wlr_buffer_end_data_ptr_access(dst);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <xf86drm.h>
|
||||
#include "config.h"
|
||||
#include "linux-drm-syncobj-v1-protocol.h"
|
||||
#include "render/dmabuf.h"
|
||||
#include "render/drm_syncobj_merger.h"
|
||||
|
||||
#define LINUX_DRM_SYNCOBJ_V1_VERSION 1
|
||||
|
|
@ -540,3 +541,12 @@ bool wlr_linux_drm_syncobj_v1_state_add_release_point(
|
|||
return wlr_drm_syncobj_merger_add(state->release_merger,
|
||||
release_timeline, release_point, event_loop);
|
||||
}
|
||||
|
||||
bool wlr_linux_drm_syncobj_v1_state_add_release_from_implicit_sync(
|
||||
struct wlr_linux_drm_syncobj_surface_v1_state *state,
|
||||
struct wlr_buffer *buffer, struct wl_event_loop *event_loop) {
|
||||
if (state->release_merger != NULL) {
|
||||
return true;
|
||||
}
|
||||
return wlr_drm_syncobj_merger_add_dmabuf(state->release_merger, buffer, event_loop);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue