mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-03-31 07:11:32 -04:00
Compare commits
24 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1d38536c9 | ||
|
|
a945fd8940 | ||
|
|
2bfbec4af1 | ||
|
|
1a9b1292e2 | ||
|
|
ad82740518 | ||
|
|
bba38a0d82 | ||
|
|
df1539d9f0 | ||
|
|
eff5aa52e6 | ||
|
|
8daba3246d | ||
|
|
52564ea97c | ||
|
|
288ba9e75b | ||
|
|
2f14845ce0 | ||
|
|
c4ff394f7f | ||
|
|
88718e84c9 | ||
|
|
6a902237ef | ||
|
|
47a43e14ae | ||
|
|
ba32abbddb | ||
|
|
9c3bfbeb48 | ||
|
|
b727521449 | ||
|
|
af228b879a | ||
|
|
ec26eb250a | ||
|
|
3105ac2b16 | ||
|
|
557fde4d01 | ||
|
|
e444836bf2 |
26 changed files with 494 additions and 141 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
include: https://git.sr.ht/~emersion/dalligi/blob/master/templates/multi.yml
|
include: https://gitlab.freedesktop.org/emersion/dalligi/-/raw/master/templates/multi.yml
|
||||||
alpine:
|
alpine:
|
||||||
extends: .dalligi
|
extends: .dalligi
|
||||||
pages: true
|
pages: true
|
||||||
|
|
|
||||||
|
|
@ -423,12 +423,6 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) {
|
||||||
if (state->primary_in_fence_fd >= 0) {
|
if (state->primary_in_fence_fd >= 0) {
|
||||||
close(state->primary_in_fence_fd);
|
close(state->primary_in_fence_fd);
|
||||||
}
|
}
|
||||||
if (state->out_fence_fd >= 0) {
|
|
||||||
// TODO: error handling
|
|
||||||
wlr_drm_syncobj_timeline_import_sync_file(state->base->signal_timeline,
|
|
||||||
state->base->signal_point, state->out_fence_fd);
|
|
||||||
close(state->out_fence_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->colorspace = state->colorspace;
|
conn->colorspace = state->colorspace;
|
||||||
}
|
}
|
||||||
|
|
@ -446,9 +440,6 @@ void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state)
|
||||||
if (state->primary_in_fence_fd >= 0) {
|
if (state->primary_in_fence_fd >= 0) {
|
||||||
close(state->primary_in_fence_fd);
|
close(state->primary_in_fence_fd);
|
||||||
}
|
}
|
||||||
if (state->out_fence_fd >= 0) {
|
|
||||||
close(state->out_fence_fd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) {
|
static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) {
|
||||||
|
|
@ -500,19 +491,6 @@ static void set_plane_in_fence_fd(struct atomic *atom,
|
||||||
atomic_add(atom, plane->id, plane->props.in_fence_fd, sync_file_fd);
|
atomic_add(atom, plane->id, plane->props.in_fence_fd, sync_file_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_crtc_out_fence_ptr(struct atomic *atom, struct wlr_drm_crtc *crtc,
|
|
||||||
int *fd_ptr) {
|
|
||||||
if (!crtc->props.out_fence_ptr) {
|
|
||||||
wlr_log(WLR_ERROR,
|
|
||||||
"CRTC %"PRIu32" is missing the OUT_FENCE_PTR property",
|
|
||||||
crtc->id);
|
|
||||||
atom->failed = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic_add(atom, crtc->id, crtc->props.out_fence_ptr, (uintptr_t)fd_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void atomic_connector_add(struct atomic *atom,
|
static void atomic_connector_add(struct atomic *atom,
|
||||||
struct wlr_drm_connector_state *state, bool modeset) {
|
struct wlr_drm_connector_state *state, bool modeset) {
|
||||||
struct wlr_drm_connector *conn = state->connector;
|
struct wlr_drm_connector *conn = state->connector;
|
||||||
|
|
@ -557,9 +535,6 @@ static void atomic_connector_add(struct atomic *atom,
|
||||||
if (state->primary_in_fence_fd >= 0) {
|
if (state->primary_in_fence_fd >= 0) {
|
||||||
set_plane_in_fence_fd(atom, crtc->primary, state->primary_in_fence_fd);
|
set_plane_in_fence_fd(atom, crtc->primary, state->primary_in_fence_fd);
|
||||||
}
|
}
|
||||||
if (state->base->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
|
|
||||||
set_crtc_out_fence_ptr(atom, crtc, &state->out_fence_fd);
|
|
||||||
}
|
|
||||||
if (crtc->cursor) {
|
if (crtc->cursor) {
|
||||||
if (drm_connector_is_cursor_visible(conn)) {
|
if (drm_connector_is_cursor_visible(conn)) {
|
||||||
struct wlr_fbox cursor_src = {
|
struct wlr_fbox cursor_src = {
|
||||||
|
|
|
||||||
|
|
@ -367,7 +367,17 @@ static void drm_plane_finish_surface(struct wlr_drm_plane *plane) {
|
||||||
}
|
}
|
||||||
|
|
||||||
drm_fb_clear(&plane->queued_fb);
|
drm_fb_clear(&plane->queued_fb);
|
||||||
|
if (plane->queued_release_timeline != NULL) {
|
||||||
|
wlr_drm_syncobj_timeline_signal(plane->queued_release_timeline, plane->queued_release_point);
|
||||||
|
wlr_drm_syncobj_timeline_unref(plane->queued_release_timeline);
|
||||||
|
plane->queued_release_timeline = NULL;
|
||||||
|
}
|
||||||
drm_fb_clear(&plane->current_fb);
|
drm_fb_clear(&plane->current_fb);
|
||||||
|
if (plane->current_release_timeline != NULL) {
|
||||||
|
wlr_drm_syncobj_timeline_signal(plane->current_release_timeline, plane->current_release_point);
|
||||||
|
wlr_drm_syncobj_timeline_unref(plane->current_release_timeline);
|
||||||
|
plane->current_release_timeline = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
finish_drm_surface(&plane->mgpu_surf);
|
finish_drm_surface(&plane->mgpu_surf);
|
||||||
}
|
}
|
||||||
|
|
@ -556,6 +566,18 @@ static void drm_connector_apply_commit(const struct wlr_drm_connector_state *sta
|
||||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||||
|
|
||||||
drm_fb_copy(&crtc->primary->queued_fb, state->primary_fb);
|
drm_fb_copy(&crtc->primary->queued_fb, state->primary_fb);
|
||||||
|
if (crtc->primary->queued_release_timeline != NULL) {
|
||||||
|
wlr_drm_syncobj_timeline_signal(crtc->primary->queued_release_timeline, crtc->primary->queued_release_point);
|
||||||
|
wlr_drm_syncobj_timeline_unref(crtc->primary->queued_release_timeline);
|
||||||
|
}
|
||||||
|
if (state->base->signal_timeline != NULL) {
|
||||||
|
crtc->primary->queued_release_timeline = wlr_drm_syncobj_timeline_ref(state->base->signal_timeline);
|
||||||
|
crtc->primary->queued_release_point = state->base->signal_point;
|
||||||
|
} else {
|
||||||
|
crtc->primary->queued_release_timeline = NULL;
|
||||||
|
crtc->primary->queued_release_point = 0;
|
||||||
|
}
|
||||||
|
|
||||||
crtc->primary->viewport = state->primary_viewport;
|
crtc->primary->viewport = state->primary_viewport;
|
||||||
if (crtc->cursor != NULL) {
|
if (crtc->cursor != NULL) {
|
||||||
drm_fb_copy(&crtc->cursor->queued_fb, state->cursor_fb);
|
drm_fb_copy(&crtc->cursor->queued_fb, state->cursor_fb);
|
||||||
|
|
@ -646,7 +668,6 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
|
||||||
.base = base,
|
.base = base,
|
||||||
.active = output_pending_enabled(&conn->output, base),
|
.active = output_pending_enabled(&conn->output, base),
|
||||||
.primary_in_fence_fd = -1,
|
.primary_in_fence_fd = -1,
|
||||||
.out_fence_fd = -1,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_output_mode *mode = conn->output.current_mode;
|
struct wlr_output_mode *mode = conn->output.current_mode;
|
||||||
|
|
@ -2018,6 +2039,14 @@ static void handle_page_flip(int fd, unsigned seq,
|
||||||
struct wlr_drm_plane *plane = conn->crtc->primary;
|
struct wlr_drm_plane *plane = conn->crtc->primary;
|
||||||
if (plane->queued_fb) {
|
if (plane->queued_fb) {
|
||||||
drm_fb_move(&plane->current_fb, &plane->queued_fb);
|
drm_fb_move(&plane->current_fb, &plane->queued_fb);
|
||||||
|
if (plane->current_release_timeline != NULL) {
|
||||||
|
wlr_drm_syncobj_timeline_signal(plane->current_release_timeline, plane->current_release_point);
|
||||||
|
wlr_drm_syncobj_timeline_unref(plane->current_release_timeline);
|
||||||
|
}
|
||||||
|
plane->current_release_timeline = plane->queued_release_timeline;
|
||||||
|
plane->current_release_point = plane->queued_release_point;
|
||||||
|
plane->queued_release_timeline = NULL;
|
||||||
|
plane->queued_release_point = 0;
|
||||||
}
|
}
|
||||||
if (conn->crtc->cursor && conn->crtc->cursor->queued_fb) {
|
if (conn->crtc->cursor && conn->crtc->cursor->queued_fb) {
|
||||||
drm_fb_move(&conn->crtc->cursor->current_fb,
|
drm_fb_move(&conn->crtc->cursor->current_fb,
|
||||||
|
|
|
||||||
|
|
@ -352,10 +352,6 @@ static bool add_connector(drmModeAtomicReq *req,
|
||||||
liftoff_layer_set_property(crtc->liftoff_composition_layer,
|
liftoff_layer_set_property(crtc->liftoff_composition_layer,
|
||||||
"IN_FENCE_FD", state->primary_in_fence_fd);
|
"IN_FENCE_FD", state->primary_in_fence_fd);
|
||||||
}
|
}
|
||||||
if (state->base->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
|
|
||||||
ok = ok && add_prop(req, crtc->id, crtc->props.out_fence_ptr,
|
|
||||||
(uintptr_t)&state->out_fence_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state->base->committed & WLR_OUTPUT_STATE_LAYERS) {
|
if (state->base->committed & WLR_OUTPUT_STATE_LAYERS) {
|
||||||
for (size_t i = 0; i < state->base->layers_len; i++) {
|
for (size_t i = 0; i < state->base->layers_len; i++) {
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ static void handle_x11_event(struct wlr_x11_backend *x11,
|
||||||
handle_x11_error(x11, ev);
|
handle_x11_error(x11, ev);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case XCB_DESTROY_NOTIFY:
|
||||||
case XCB_UNMAP_NOTIFY:
|
case XCB_UNMAP_NOTIFY:
|
||||||
case XCB_MAP_NOTIFY:
|
case XCB_MAP_NOTIFY:
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,12 @@ struct wlr_drm_plane {
|
||||||
|
|
||||||
/* Buffer submitted to the kernel, will be presented on next vblank */
|
/* Buffer submitted to the kernel, will be presented on next vblank */
|
||||||
struct wlr_drm_fb *queued_fb;
|
struct wlr_drm_fb *queued_fb;
|
||||||
|
struct wlr_drm_syncobj_timeline *queued_release_timeline;
|
||||||
|
uint64_t queued_release_point;
|
||||||
/* Buffer currently displayed on screen */
|
/* Buffer currently displayed on screen */
|
||||||
struct wlr_drm_fb *current_fb;
|
struct wlr_drm_fb *current_fb;
|
||||||
|
struct wlr_drm_syncobj_timeline *current_release_timeline;
|
||||||
|
uint64_t current_release_point;
|
||||||
/* Viewport belonging to the last committed fb */
|
/* Viewport belonging to the last committed fb */
|
||||||
struct wlr_drm_viewport viewport;
|
struct wlr_drm_viewport viewport;
|
||||||
|
|
||||||
|
|
@ -156,7 +160,7 @@ struct wlr_drm_connector_state {
|
||||||
uint32_t mode_id;
|
uint32_t mode_id;
|
||||||
uint32_t gamma_lut;
|
uint32_t gamma_lut;
|
||||||
uint32_t fb_damage_clips;
|
uint32_t fb_damage_clips;
|
||||||
int primary_in_fence_fd, out_fence_fd;
|
int primary_in_fence_fd;
|
||||||
bool vrr_enabled;
|
bool vrr_enabled;
|
||||||
uint32_t colorspace;
|
uint32_t colorspace;
|
||||||
uint32_t hdr_output_metadata;
|
uint32_t hdr_output_metadata;
|
||||||
|
|
|
||||||
44
include/render/drm_syncobj_merger.h
Normal file
44
include/render/drm_syncobj_merger.h
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef WLR_RENDER_DRM_SYNCOBJ_MERGER_H
|
||||||
|
#define WLR_RENDER_DRM_SYNCOBJ_MERGER_H
|
||||||
|
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accumulate timeline points, to have a destination timeline point be
|
||||||
|
* signalled when all inputs are
|
||||||
|
*/
|
||||||
|
struct wlr_drm_syncobj_merger {
|
||||||
|
int n_ref;
|
||||||
|
struct wlr_drm_syncobj_timeline *dst_timeline;
|
||||||
|
uint64_t dst_point;
|
||||||
|
int sync_fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new merger.
|
||||||
|
*
|
||||||
|
* The given timeline point will be signalled when all input points are
|
||||||
|
* signalled and the merger is destroyed.
|
||||||
|
*/
|
||||||
|
struct wlr_drm_syncobj_merger *wlr_drm_syncobj_merger_create(
|
||||||
|
struct wlr_drm_syncobj_timeline *dst_timeline, uint64_t dst_point);
|
||||||
|
|
||||||
|
struct wlr_drm_syncobj_merger *wlr_drm_syncobj_merger_ref(
|
||||||
|
struct wlr_drm_syncobj_merger *merger);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target timeline point is materialized when all inputs are, and the merger is
|
||||||
|
* destroyed.
|
||||||
|
*/
|
||||||
|
void wlr_drm_syncobj_merger_unref(struct wlr_drm_syncobj_merger *merger);
|
||||||
|
/**
|
||||||
|
* Add a new timeline point to wait for.
|
||||||
|
*
|
||||||
|
* If the point is not materialized, the supplied event loop is used to schedule
|
||||||
|
* a wait.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -90,6 +90,10 @@ bool wlr_drm_syncobj_timeline_transfer(struct wlr_drm_syncobj_timeline *dst,
|
||||||
*/
|
*/
|
||||||
bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline,
|
bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline,
|
||||||
uint64_t point, uint32_t flags, bool *result);
|
uint64_t point, uint32_t flags, bool *result);
|
||||||
|
/**
|
||||||
|
* Signals a timeline point.
|
||||||
|
*/
|
||||||
|
bool wlr_drm_syncobj_timeline_signal(struct wlr_drm_syncobj_timeline *timeline, uint64_t point);
|
||||||
/**
|
/**
|
||||||
* Asynchronously wait for a timeline point.
|
* Asynchronously wait for a timeline point.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,12 @@ struct wlr_linux_drm_syncobj_surface_v1_state {
|
||||||
struct wlr_drm_syncobj_timeline *acquire_timeline;
|
struct wlr_drm_syncobj_timeline *acquire_timeline;
|
||||||
uint64_t acquire_point;
|
uint64_t acquire_point;
|
||||||
|
|
||||||
struct wlr_drm_syncobj_timeline *release_timeline;
|
struct {
|
||||||
uint64_t release_point;
|
bool committed;
|
||||||
|
struct wlr_drm_syncobj_timeline *release_timeline;
|
||||||
|
uint64_t release_point;
|
||||||
|
struct wlr_drm_syncobj_merger *release_merger;
|
||||||
|
} WLR_PRIVATE;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_linux_drm_syncobj_manager_v1 {
|
struct wlr_linux_drm_syncobj_manager_v1 {
|
||||||
|
|
@ -55,4 +59,19 @@ struct wlr_linux_drm_syncobj_surface_v1_state *wlr_linux_drm_syncobj_v1_get_surf
|
||||||
bool wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(
|
bool wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(
|
||||||
struct wlr_linux_drm_syncobj_surface_v1_state *state, struct wlr_buffer *buffer);
|
struct wlr_linux_drm_syncobj_surface_v1_state *state, struct wlr_buffer *buffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a release point for buffer usage.
|
||||||
|
*
|
||||||
|
* 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 given release point may not be materialized, a wl_event_loop must
|
||||||
|
* be supplied to schedule a wait internally, if needed
|
||||||
|
*/
|
||||||
|
bool wlr_linux_drm_syncobj_v1_state_add_release_point(
|
||||||
|
struct wlr_linux_drm_syncobj_surface_v1_state *state,
|
||||||
|
struct wlr_drm_syncobj_timeline *release_timeline, uint64_t release_point,
|
||||||
|
struct wl_event_loop *event_loop);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -131,8 +131,6 @@ struct wlr_scene_surface {
|
||||||
struct wlr_addon addon;
|
struct wlr_addon addon;
|
||||||
|
|
||||||
struct wl_listener outputs_update;
|
struct wl_listener outputs_update;
|
||||||
struct wl_listener output_enter;
|
|
||||||
struct wl_listener output_leave;
|
|
||||||
struct wl_listener output_sample;
|
struct wl_listener output_sample;
|
||||||
struct wl_listener frame_done;
|
struct wl_listener frame_done;
|
||||||
struct wl_listener surface_destroy;
|
struct wl_listener surface_destroy;
|
||||||
|
|
@ -155,6 +153,8 @@ struct wlr_scene_outputs_update_event {
|
||||||
struct wlr_scene_output_sample_event {
|
struct wlr_scene_output_sample_event {
|
||||||
struct wlr_scene_output *output;
|
struct wlr_scene_output *output;
|
||||||
bool direct_scanout;
|
bool direct_scanout;
|
||||||
|
struct wlr_drm_syncobj_timeline *release_timeline;
|
||||||
|
uint64_t release_point;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_scene_frame_done_event {
|
struct wlr_scene_frame_done_event {
|
||||||
|
|
@ -268,6 +268,8 @@ struct wlr_scene_output {
|
||||||
|
|
||||||
struct wlr_drm_syncobj_timeline *in_timeline;
|
struct wlr_drm_syncobj_timeline *in_timeline;
|
||||||
uint64_t in_point;
|
uint64_t in_point;
|
||||||
|
struct wlr_drm_syncobj_timeline *out_timeline;
|
||||||
|
uint64_t out_point;
|
||||||
} WLR_PRIVATE;
|
} WLR_PRIVATE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,27 @@ struct wlr_virtual_keyboard_v1 {
|
||||||
bool has_keymap;
|
bool has_keymap;
|
||||||
|
|
||||||
struct wl_list link; // wlr_virtual_keyboard_manager_v1.virtual_keyboards
|
struct wl_list link; // wlr_virtual_keyboard_manager_v1.virtual_keyboards
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_listener seat_destroy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_virtual_keyboard_manager_v1* wlr_virtual_keyboard_manager_v1_create(
|
struct wlr_virtual_keyboard_manager_v1* wlr_virtual_keyboard_manager_v1_create(
|
||||||
struct wl_display *display);
|
struct wl_display *display);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the struct wlr_virtual_keyboard_v1 corresponding to a zwp_virtual_keyboard_v1 resource.
|
||||||
|
*
|
||||||
|
* Asserts that the resource is a valid zwp_virtual_keyboard_v1 resource created by wlroots.
|
||||||
|
*
|
||||||
|
* Returns NULL if the resource is inert.
|
||||||
|
*/
|
||||||
|
struct wlr_virtual_keyboard_v1 *wlr_virtual_keyboard_v1_from_resource(
|
||||||
|
struct wl_resource *resource);
|
||||||
|
|
||||||
struct wlr_virtual_keyboard_v1 *wlr_input_device_get_virtual_keyboard(
|
struct wlr_virtual_keyboard_v1 *wlr_input_device_get_virtual_keyboard(
|
||||||
struct wlr_input_device *wlr_dev);
|
struct wlr_input_device *wlr_dev);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
project(
|
project(
|
||||||
'wlroots',
|
'wlroots',
|
||||||
'c',
|
'c',
|
||||||
version: '0.20.0-rc4',
|
version: '0.20.0',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
meson_version: '>=1.3',
|
meson_version: '>=1.3',
|
||||||
default_options: [
|
default_options: [
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@
|
||||||
|
|
||||||
<request name="destroy" type="destructor">
|
<request name="destroy" type="destructor">
|
||||||
<description summary="delete this object, used or not">
|
<description summary="delete this object, used or not">
|
||||||
Unreferences the frame. This request must be called as soon as its no
|
Unreferences the frame. This request must be called as soon as it's no
|
||||||
longer used.
|
longer used.
|
||||||
|
|
||||||
It can be called at any time by the client. The client will still have
|
It can be called at any time by the client. The client will still have
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,14 @@ bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wlr_drm_syncobj_timeline_signal(struct wlr_drm_syncobj_timeline *timeline, uint64_t point) {
|
||||||
|
if (drmSyncobjTimelineSignal(timeline->drm_fd, &timeline->handle, &point, 1) != 0) {
|
||||||
|
wlr_log(WLR_ERROR, "drmSyncobjTimelineSignal() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static int handle_eventfd_ready(int ev_fd, uint32_t mask, void *data) {
|
static int handle_eventfd_ready(int ev_fd, uint32_t mask, void *data) {
|
||||||
struct wlr_drm_syncobj_timeline_waiter *waiter = data;
|
struct wlr_drm_syncobj_timeline_waiter *waiter = data;
|
||||||
|
|
||||||
|
|
|
||||||
133
render/drm_syncobj_merger.c
Normal file
133
render/drm_syncobj_merger.c
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wayland-util.h>
|
||||||
|
#include <wlr/render/drm_syncobj.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include "render/drm_syncobj_merger.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#if HAVE_LINUX_SYNC_FILE
|
||||||
|
|
||||||
|
#include <linux/sync_file.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
static int sync_file_merge(int fd1, int fd2) {
|
||||||
|
// The kernel will automatically prune signalled fences
|
||||||
|
struct sync_merge_data merge_data = { .fd2 = fd2 };
|
||||||
|
if (ioctl(fd1, SYNC_IOC_MERGE, &merge_data) < 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "ioctl(SYNC_IOC_MERGE) failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return merge_data.fence;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static int sync_file_merge(int fd1, int fd2) {
|
||||||
|
wlr_log(WLR_ERROR, "sync_file support is unavailable");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct wlr_drm_syncobj_merger *wlr_drm_syncobj_merger_create(
|
||||||
|
struct wlr_drm_syncobj_timeline *dst_timeline, uint64_t dst_point) {
|
||||||
|
struct wlr_drm_syncobj_merger *merger = calloc(1, sizeof(*merger));
|
||||||
|
if (merger == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
merger->n_ref = 1;
|
||||||
|
merger->dst_timeline = wlr_drm_syncobj_timeline_ref(dst_timeline);
|
||||||
|
merger->dst_point = dst_point;
|
||||||
|
merger->sync_fd = -1;
|
||||||
|
return merger;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drm_syncobj_merger *wlr_drm_syncobj_merger_ref(
|
||||||
|
struct wlr_drm_syncobj_merger *merger) {
|
||||||
|
assert(merger->n_ref > 0);
|
||||||
|
merger->n_ref++;
|
||||||
|
return merger;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drm_syncobj_merger_unref(struct wlr_drm_syncobj_merger *merger) {
|
||||||
|
if (merger == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(merger->n_ref > 0);
|
||||||
|
merger->n_ref--;
|
||||||
|
if (merger->n_ref > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (merger->sync_fd != -1) {
|
||||||
|
wlr_drm_syncobj_timeline_import_sync_file(merger->dst_timeline,
|
||||||
|
merger->dst_point, merger->sync_fd);
|
||||||
|
close(merger->sync_fd);
|
||||||
|
} else {
|
||||||
|
wlr_drm_syncobj_timeline_signal(merger->dst_timeline, merger->dst_point);
|
||||||
|
}
|
||||||
|
wlr_drm_syncobj_timeline_unref(merger->dst_timeline);
|
||||||
|
free(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct export_waiter {
|
||||||
|
struct wlr_drm_syncobj_timeline_waiter waiter;
|
||||||
|
struct wlr_drm_syncobj_merger *merger;
|
||||||
|
struct wlr_drm_syncobj_timeline *src_timeline;
|
||||||
|
uint64_t src_point;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void export_waiter_handle_ready(struct wlr_drm_syncobj_timeline_waiter *waiter) {
|
||||||
|
struct export_waiter *add = wl_container_of(waiter, add, waiter);
|
||||||
|
merger_add_exportable(add->merger, add->src_timeline, add->src_point);
|
||||||
|
wlr_drm_syncobj_merger_unref(add->merger);
|
||||||
|
wlr_drm_syncobj_timeline_unref(add->src_timeline);
|
||||||
|
wlr_drm_syncobj_timeline_waiter_finish(&add->waiter);
|
||||||
|
free(add);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_drm_syncobj_merger_add(struct wlr_drm_syncobj_merger *merger,
|
||||||
|
struct wlr_drm_syncobj_timeline *src_timeline, uint64_t src_point,
|
||||||
|
struct wl_event_loop *loop) {
|
||||||
|
assert(loop != NULL);
|
||||||
|
bool exportable = false;
|
||||||
|
int flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE;
|
||||||
|
if (!wlr_drm_syncobj_timeline_check(src_timeline, src_point, flags, &exportable)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (exportable) {
|
||||||
|
return merger_add_exportable(merger, src_timeline, src_point);
|
||||||
|
}
|
||||||
|
struct export_waiter *add = calloc(1, sizeof(*add));
|
||||||
|
if (add == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_drm_syncobj_timeline_waiter_init(&add->waiter, src_timeline, src_point,
|
||||||
|
flags, loop, export_waiter_handle_ready)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
add->merger = merger;
|
||||||
|
add->src_timeline = wlr_drm_syncobj_timeline_ref(src_timeline);
|
||||||
|
add->src_point = src_point;
|
||||||
|
merger->n_ref++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@ wlr_files += files(
|
||||||
'color.c',
|
'color.c',
|
||||||
'dmabuf.c',
|
'dmabuf.c',
|
||||||
'drm_format_set.c',
|
'drm_format_set.c',
|
||||||
|
'drm_syncobj_merger.c',
|
||||||
'drm_syncobj.c',
|
'drm_syncobj.c',
|
||||||
'pass.c',
|
'pass.c',
|
||||||
'pixel_format.c',
|
'pixel_format.c',
|
||||||
|
|
@ -28,6 +29,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
internal_config.set10('HAVE_EVENTFD', cc.has_header('sys/eventfd.h'))
|
internal_config.set10('HAVE_EVENTFD', cc.has_header('sys/eventfd.h'))
|
||||||
|
internal_config.set10('HAVE_LINUX_SYNC_FILE', cc.has_header('linux/sync_file.h'))
|
||||||
|
|
||||||
if 'gles2' in renderers or 'auto' in renderers
|
if 'gles2' in renderers or 'auto' in renderers
|
||||||
egl = dependency('egl', required: 'gles2' in renderers)
|
egl = dependency('egl', required: 'gles2' in renderers)
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ const char *vulkan_strerror(VkResult err) {
|
||||||
ERR_STR(ERROR_INVALID_EXTERNAL_HANDLE);
|
ERR_STR(ERROR_INVALID_EXTERNAL_HANDLE);
|
||||||
ERR_STR(ERROR_FRAGMENTATION);
|
ERR_STR(ERROR_FRAGMENTATION);
|
||||||
ERR_STR(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS);
|
ERR_STR(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS);
|
||||||
ERR_STR(PIPELINE_COMPILE_REQUIRED);
|
ERR_STR(PIPELINE_COMPILE_REQUIRED_EXT);
|
||||||
ERR_STR(ERROR_SURFACE_LOST_KHR);
|
ERR_STR(ERROR_SURFACE_LOST_KHR);
|
||||||
ERR_STR(ERROR_NATIVE_WINDOW_IN_USE_KHR);
|
ERR_STR(ERROR_NATIVE_WINDOW_IN_USE_KHR);
|
||||||
ERR_STR(SUBOPTIMAL_KHR);
|
ERR_STR(SUBOPTIMAL_KHR);
|
||||||
|
|
|
||||||
|
|
@ -564,17 +564,17 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
|
||||||
.pQueuePriorities = &prio,
|
.pQueuePriorities = &prio,
|
||||||
};
|
};
|
||||||
|
|
||||||
VkDeviceQueueGlobalPriorityCreateInfoKHR global_priority;
|
VkDeviceQueueGlobalPriorityCreateInfoEXT global_priority;
|
||||||
bool has_global_priority = check_extension(avail_ext_props, avail_extc,
|
bool has_global_priority = check_extension(avail_ext_props, avail_extc,
|
||||||
VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME);
|
VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME);
|
||||||
if (has_global_priority) {
|
if (has_global_priority) {
|
||||||
// If global priorities are supported, request a high-priority context
|
// If global priorities are supported, request a high-priority context
|
||||||
global_priority = (VkDeviceQueueGlobalPriorityCreateInfoKHR){
|
global_priority = (VkDeviceQueueGlobalPriorityCreateInfoEXT){
|
||||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT,
|
||||||
.globalPriority = VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR,
|
.globalPriority = VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT,
|
||||||
};
|
};
|
||||||
qinfo.pNext = &global_priority;
|
qinfo.pNext = &global_priority;
|
||||||
extensions[extensions_len++] = VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME;
|
extensions[extensions_len++] = VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME;
|
||||||
wlr_log(WLR_DEBUG, "Requesting a high-priority device queue");
|
wlr_log(WLR_DEBUG, "Requesting a high-priority device queue");
|
||||||
} else {
|
} else {
|
||||||
wlr_log(WLR_DEBUG, "Global priorities are not supported, "
|
wlr_log(WLR_DEBUG, "Global priorities are not supported, "
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,10 @@ static const struct wlr_ext_image_capture_source_v1_interface output_source_impl
|
||||||
static void source_update_buffer_constraints(struct wlr_ext_output_image_capture_source_v1 *source) {
|
static void source_update_buffer_constraints(struct wlr_ext_output_image_capture_source_v1 *source) {
|
||||||
struct wlr_output *output = source->output;
|
struct wlr_output *output = source->output;
|
||||||
|
|
||||||
|
if (!output->enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!wlr_output_configure_primary_swapchain(output, NULL, &output->swapchain)) {
|
if (!wlr_output_configure_primary_swapchain(output, NULL, &output->swapchain)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -123,7 +127,8 @@ static void source_handle_output_commit(struct wl_listener *listener,
|
||||||
struct wlr_ext_output_image_capture_source_v1 *source = wl_container_of(listener, source, output_commit);
|
struct wlr_ext_output_image_capture_source_v1 *source = wl_container_of(listener, source, output_commit);
|
||||||
struct wlr_output_event_commit *event = data;
|
struct wlr_output_event_commit *event = data;
|
||||||
|
|
||||||
if (event->state->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_RENDER_FORMAT)) {
|
if (event->state->committed & (WLR_OUTPUT_STATE_MODE |
|
||||||
|
WLR_OUTPUT_STATE_RENDER_FORMAT | WLR_OUTPUT_STATE_ENABLED)) {
|
||||||
source_update_buffer_constraints(source);
|
source_update_buffer_constraints(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ static struct wlr_output *get_surface_frame_pacing_output(struct wlr_surface *su
|
||||||
return frame_pacing_output;
|
return frame_pacing_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool get_tf_preference(enum wlr_color_transfer_function tf) {
|
static int get_tf_preference(enum wlr_color_transfer_function tf) {
|
||||||
switch (tf) {
|
switch (tf) {
|
||||||
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -52,7 +52,7 @@ static bool get_tf_preference(enum wlr_color_transfer_function tf) {
|
||||||
abort(); // unreachable
|
abort(); // unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool get_primaries_preference(enum wlr_color_named_primaries primaries) {
|
static int get_primaries_preference(enum wlr_color_named_primaries primaries) {
|
||||||
switch (primaries) {
|
switch (primaries) {
|
||||||
case WLR_COLOR_NAMED_PRIMARIES_SRGB:
|
case WLR_COLOR_NAMED_PRIMARIES_SRGB:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -94,14 +94,44 @@ static void handle_scene_buffer_outputs_update(
|
||||||
struct wl_listener *listener, void *data) {
|
struct wl_listener *listener, void *data) {
|
||||||
struct wlr_scene_surface *surface =
|
struct wlr_scene_surface *surface =
|
||||||
wl_container_of(listener, surface, outputs_update);
|
wl_container_of(listener, surface, outputs_update);
|
||||||
|
struct wlr_scene_outputs_update_event *event = data;
|
||||||
struct wlr_scene *scene = scene_node_get_root(&surface->buffer->node);
|
struct wlr_scene *scene = scene_node_get_root(&surface->buffer->node);
|
||||||
|
|
||||||
// If the surface is no longer visible on any output, keep the last sent
|
// If the surface is no longer visible on any output, keep the last sent
|
||||||
// preferred configuration to avoid unnecessary redraws
|
// preferred configuration to avoid unnecessary redraws
|
||||||
if (wl_list_empty(&surface->surface->current_outputs)) {
|
if (event->size == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To avoid sending redundant leave/enter events when a surface is hidden and then shown
|
||||||
|
// without moving to a different output the following policy is implemented:
|
||||||
|
//
|
||||||
|
// 1. When a surface transitions from being visible on >0 outputs to being visible on 0 outputs
|
||||||
|
// don't send any leave events.
|
||||||
|
//
|
||||||
|
// 2. When a surface transitions from being visible on 0 outputs to being visible on >0 outputs
|
||||||
|
// send leave events for all entered outputs on which the surface is no longer visible as
|
||||||
|
// well as enter events for any outputs not already entered.
|
||||||
|
struct wlr_surface_output *entered_output, *tmp;
|
||||||
|
wl_list_for_each_safe(entered_output, tmp, &surface->surface->current_outputs, link) {
|
||||||
|
bool active = false;
|
||||||
|
for (size_t i = 0; i < event->size; i++) {
|
||||||
|
if (entered_output->output == event->active[i]->output) {
|
||||||
|
active = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!active) {
|
||||||
|
wlr_surface_send_leave(surface->surface, entered_output->output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < event->size; i++) {
|
||||||
|
// This function internally checks if an enter event was already sent for the output
|
||||||
|
// to avoid sending redundant events.
|
||||||
|
wlr_surface_send_enter(surface->surface, event->active[i]->output);
|
||||||
|
}
|
||||||
|
|
||||||
double scale = get_surface_preferred_buffer_scale(surface->surface);
|
double scale = get_surface_preferred_buffer_scale(surface->surface);
|
||||||
wlr_fractional_scale_v1_notify_scale(surface->surface, scale);
|
wlr_fractional_scale_v1_notify_scale(surface->surface, scale);
|
||||||
wlr_surface_set_preferred_buffer_scale(surface->surface, ceil(scale));
|
wlr_surface_set_preferred_buffer_scale(surface->surface, ceil(scale));
|
||||||
|
|
@ -114,24 +144,6 @@ static void handle_scene_buffer_outputs_update(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_scene_buffer_output_enter(
|
|
||||||
struct wl_listener *listener, void *data) {
|
|
||||||
struct wlr_scene_surface *surface =
|
|
||||||
wl_container_of(listener, surface, output_enter);
|
|
||||||
struct wlr_scene_output *output = data;
|
|
||||||
|
|
||||||
wlr_surface_send_enter(surface->surface, output->output);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_scene_buffer_output_leave(
|
|
||||||
struct wl_listener *listener, void *data) {
|
|
||||||
struct wlr_scene_surface *surface =
|
|
||||||
wl_container_of(listener, surface, output_leave);
|
|
||||||
struct wlr_scene_output *output = data;
|
|
||||||
|
|
||||||
wlr_surface_send_leave(surface->surface, output->output);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_scene_buffer_output_sample(
|
static void handle_scene_buffer_output_sample(
|
||||||
struct wl_listener *listener, void *data) {
|
struct wl_listener *listener, void *data) {
|
||||||
struct wlr_scene_surface *surface =
|
struct wlr_scene_surface *surface =
|
||||||
|
|
@ -147,6 +159,13 @@ static void handle_scene_buffer_output_sample(
|
||||||
} else {
|
} else {
|
||||||
wlr_presentation_surface_textured_on_output(surface->surface, output);
|
wlr_presentation_surface_textured_on_output(surface->surface, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wlr_linux_drm_syncobj_surface_v1_state *syncobj_surface_state =
|
||||||
|
wlr_linux_drm_syncobj_v1_get_surface_state(surface->surface);
|
||||||
|
if (syncobj_surface_state != NULL && event->release_timeline != NULL) {
|
||||||
|
wlr_linux_drm_syncobj_v1_state_add_release_point(syncobj_surface_state,
|
||||||
|
event->release_timeline, event->release_point, output->event_loop);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_scene_buffer_frame_done(
|
static void handle_scene_buffer_frame_done(
|
||||||
|
|
@ -311,27 +330,15 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
|
||||||
struct wlr_linux_drm_syncobj_surface_v1_state *syncobj_surface_state =
|
struct wlr_linux_drm_syncobj_surface_v1_state *syncobj_surface_state =
|
||||||
wlr_linux_drm_syncobj_v1_get_surface_state(surface);
|
wlr_linux_drm_syncobj_v1_get_surface_state(surface);
|
||||||
|
|
||||||
struct wlr_drm_syncobj_timeline *wait_timeline = NULL;
|
|
||||||
uint64_t wait_point = 0;
|
|
||||||
if (syncobj_surface_state != NULL) {
|
|
||||||
wait_timeline = syncobj_surface_state->acquire_timeline;
|
|
||||||
wait_point = syncobj_surface_state->acquire_point;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct wlr_scene_buffer_set_buffer_options options = {
|
struct wlr_scene_buffer_set_buffer_options options = {
|
||||||
.damage = &surface->buffer_damage,
|
.damage = &surface->buffer_damage,
|
||||||
.wait_timeline = wait_timeline,
|
|
||||||
.wait_point = wait_point,
|
|
||||||
};
|
};
|
||||||
|
if (syncobj_surface_state != NULL) {
|
||||||
|
options.wait_timeline = syncobj_surface_state->acquire_timeline;
|
||||||
|
options.wait_point = syncobj_surface_state->acquire_point;
|
||||||
|
}
|
||||||
wlr_scene_buffer_set_buffer_with_options(scene_buffer,
|
wlr_scene_buffer_set_buffer_with_options(scene_buffer,
|
||||||
&surface->buffer->base, &options);
|
&surface->buffer->base, &options);
|
||||||
|
|
||||||
if (syncobj_surface_state != NULL &&
|
|
||||||
(surface->current.committed & WLR_SURFACE_STATE_BUFFER) &&
|
|
||||||
surface->buffer->source != NULL) {
|
|
||||||
wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(syncobj_surface_state,
|
|
||||||
surface->buffer->source);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
wlr_scene_buffer_set_buffer(scene_buffer, NULL);
|
wlr_scene_buffer_set_buffer(scene_buffer, NULL);
|
||||||
}
|
}
|
||||||
|
|
@ -380,8 +387,6 @@ static void surface_addon_destroy(struct wlr_addon *addon) {
|
||||||
wlr_addon_finish(&surface->addon);
|
wlr_addon_finish(&surface->addon);
|
||||||
|
|
||||||
wl_list_remove(&surface->outputs_update.link);
|
wl_list_remove(&surface->outputs_update.link);
|
||||||
wl_list_remove(&surface->output_enter.link);
|
|
||||||
wl_list_remove(&surface->output_leave.link);
|
|
||||||
wl_list_remove(&surface->output_sample.link);
|
wl_list_remove(&surface->output_sample.link);
|
||||||
wl_list_remove(&surface->frame_done.link);
|
wl_list_remove(&surface->frame_done.link);
|
||||||
wl_list_remove(&surface->surface_destroy.link);
|
wl_list_remove(&surface->surface_destroy.link);
|
||||||
|
|
@ -427,12 +432,6 @@ struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_tree *parent
|
||||||
surface->outputs_update.notify = handle_scene_buffer_outputs_update;
|
surface->outputs_update.notify = handle_scene_buffer_outputs_update;
|
||||||
wl_signal_add(&scene_buffer->events.outputs_update, &surface->outputs_update);
|
wl_signal_add(&scene_buffer->events.outputs_update, &surface->outputs_update);
|
||||||
|
|
||||||
surface->output_enter.notify = handle_scene_buffer_output_enter;
|
|
||||||
wl_signal_add(&scene_buffer->events.output_enter, &surface->output_enter);
|
|
||||||
|
|
||||||
surface->output_leave.notify = handle_scene_buffer_output_leave;
|
|
||||||
wl_signal_add(&scene_buffer->events.output_leave, &surface->output_leave);
|
|
||||||
|
|
||||||
surface->output_sample.notify = handle_scene_buffer_output_sample;
|
surface->output_sample.notify = handle_scene_buffer_output_sample;
|
||||||
wl_signal_add(&scene_buffer->events.output_sample, &surface->output_sample);
|
wl_signal_add(&scene_buffer->events.output_sample, &surface->output_sample);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1553,6 +1553,8 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
|
||||||
struct wlr_scene_output_sample_event sample_event = {
|
struct wlr_scene_output_sample_event sample_event = {
|
||||||
.output = data->output,
|
.output = data->output,
|
||||||
.direct_scanout = false,
|
.direct_scanout = false,
|
||||||
|
.release_timeline = data->output->in_timeline,
|
||||||
|
.release_point = data->output->in_point,
|
||||||
};
|
};
|
||||||
wl_signal_emit_mutable(&scene_buffer->events.output_sample, &sample_event);
|
wl_signal_emit_mutable(&scene_buffer->events.output_sample, &sample_event);
|
||||||
|
|
||||||
|
|
@ -1785,7 +1787,10 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene,
|
||||||
if (drm_fd >= 0 && output->backend->features.timeline &&
|
if (drm_fd >= 0 && output->backend->features.timeline &&
|
||||||
output->renderer != NULL && output->renderer->features.timeline) {
|
output->renderer != NULL && output->renderer->features.timeline) {
|
||||||
scene_output->in_timeline = wlr_drm_syncobj_timeline_create(drm_fd);
|
scene_output->in_timeline = wlr_drm_syncobj_timeline_create(drm_fd);
|
||||||
if (scene_output->in_timeline == NULL) {
|
scene_output->out_timeline = wlr_drm_syncobj_timeline_create(drm_fd);
|
||||||
|
if (scene_output->in_timeline == NULL || scene_output->out_timeline == NULL) {
|
||||||
|
wlr_drm_syncobj_timeline_unref(scene_output->in_timeline);
|
||||||
|
wlr_drm_syncobj_timeline_unref(scene_output->out_timeline);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1840,7 +1845,14 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) {
|
||||||
wl_list_remove(&scene_output->output_commit.link);
|
wl_list_remove(&scene_output->output_commit.link);
|
||||||
wl_list_remove(&scene_output->output_damage.link);
|
wl_list_remove(&scene_output->output_damage.link);
|
||||||
wl_list_remove(&scene_output->output_needs_frame.link);
|
wl_list_remove(&scene_output->output_needs_frame.link);
|
||||||
wlr_drm_syncobj_timeline_unref(scene_output->in_timeline);
|
if (scene_output->in_timeline != NULL) {
|
||||||
|
wlr_drm_syncobj_timeline_signal(scene_output->in_timeline, UINT64_MAX);
|
||||||
|
wlr_drm_syncobj_timeline_unref(scene_output->in_timeline);
|
||||||
|
}
|
||||||
|
if (scene_output->out_timeline != NULL) {
|
||||||
|
wlr_drm_syncobj_timeline_signal(scene_output->out_timeline, UINT64_MAX);
|
||||||
|
wlr_drm_syncobj_timeline_unref(scene_output->out_timeline);
|
||||||
|
}
|
||||||
wlr_color_transform_unref(scene_output->gamma_lut_color_transform);
|
wlr_color_transform_unref(scene_output->gamma_lut_color_transform);
|
||||||
wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform);
|
wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform);
|
||||||
wlr_color_transform_unref(scene_output->prev_supplied_color_transform);
|
wlr_color_transform_unref(scene_output->prev_supplied_color_transform);
|
||||||
|
|
@ -2136,6 +2148,12 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout(
|
||||||
if (buffer->wait_timeline != NULL) {
|
if (buffer->wait_timeline != NULL) {
|
||||||
wlr_output_state_set_wait_timeline(&pending, buffer->wait_timeline, buffer->wait_point);
|
wlr_output_state_set_wait_timeline(&pending, buffer->wait_timeline, buffer->wait_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scene_output->out_timeline) {
|
||||||
|
scene_output->out_point++;
|
||||||
|
wlr_output_state_set_signal_timeline(&pending, scene_output->out_timeline, scene_output->out_point);
|
||||||
|
}
|
||||||
|
|
||||||
if (!wlr_output_test_state(scene_output->output, &pending)) {
|
if (!wlr_output_test_state(scene_output->output, &pending)) {
|
||||||
wlr_output_state_finish(&pending);
|
wlr_output_state_finish(&pending);
|
||||||
return SCANOUT_CANDIDATE;
|
return SCANOUT_CANDIDATE;
|
||||||
|
|
@ -2147,6 +2165,8 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout(
|
||||||
struct wlr_scene_output_sample_event sample_event = {
|
struct wlr_scene_output_sample_event sample_event = {
|
||||||
.output = scene_output,
|
.output = scene_output,
|
||||||
.direct_scanout = true,
|
.direct_scanout = true,
|
||||||
|
.release_timeline = data->output->out_timeline,
|
||||||
|
.release_point = data->output->out_point,
|
||||||
};
|
};
|
||||||
wl_signal_emit_mutable(&buffer->events.output_sample, &sample_event);
|
wl_signal_emit_mutable(&buffer->events.output_sample, &sample_event);
|
||||||
return SCANOUT_SUCCESS;
|
return SCANOUT_SUCCESS;
|
||||||
|
|
@ -2606,6 +2626,9 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||||
if (scene_output->in_timeline != NULL) {
|
if (scene_output->in_timeline != NULL) {
|
||||||
wlr_output_state_set_wait_timeline(state, scene_output->in_timeline,
|
wlr_output_state_set_wait_timeline(state, scene_output->in_timeline,
|
||||||
scene_output->in_point);
|
scene_output->in_point);
|
||||||
|
scene_output->out_point++;
|
||||||
|
wlr_output_state_set_signal_timeline(state, scene_output->out_timeline,
|
||||||
|
scene_output->out_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!render_gamma_lut) {
|
if (!render_gamma_lut) {
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,41 @@ static float decode_cie1931_coord(int32_t raw) {
|
||||||
return (float)raw / (1000 * 1000);
|
return (float)raw / (1000 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool cie1931_xy_equal(const struct wlr_color_cie1931_xy *a,
|
||||||
|
const struct wlr_color_cie1931_xy *b) {
|
||||||
|
return a->x == b->x && a->y == b->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool primaries_equal(const struct wlr_color_primaries *a,
|
||||||
|
const struct wlr_color_primaries *b) {
|
||||||
|
return cie1931_xy_equal(&a->red, &b->red) &&
|
||||||
|
cie1931_xy_equal(&a->green, &b->green) &&
|
||||||
|
cie1931_xy_equal(&a->blue, &b->blue) &&
|
||||||
|
cie1931_xy_equal(&a->white, &b->white);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool img_desc_data_equal(const struct wlr_image_description_v1_data *a,
|
||||||
|
const struct wlr_image_description_v1_data *b) {
|
||||||
|
if (a->tf_named != b->tf_named ||
|
||||||
|
a->primaries_named != b->primaries_named ||
|
||||||
|
a->has_mastering_display_primaries != b->has_mastering_display_primaries ||
|
||||||
|
a->has_mastering_luminance != b->has_mastering_luminance ||
|
||||||
|
a->max_cll != b->max_cll ||
|
||||||
|
a->max_fall != b->max_fall) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (a->has_mastering_display_primaries &&
|
||||||
|
!primaries_equal(&a->mastering_display_primaries, &b->mastering_display_primaries)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (a->has_mastering_luminance &&
|
||||||
|
(a->mastering_luminance.min != b->mastering_luminance.min ||
|
||||||
|
a->mastering_luminance.max != b->mastering_luminance.max)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct wp_image_description_v1_interface image_desc_impl;
|
static const struct wp_image_description_v1_interface image_desc_impl;
|
||||||
|
|
||||||
static struct wlr_image_description_v1 *image_desc_from_resource(struct wl_resource *resource) {
|
static struct wlr_image_description_v1 *image_desc_from_resource(struct wl_resource *resource) {
|
||||||
|
|
@ -1002,16 +1037,20 @@ void wlr_color_manager_v1_set_surface_preferred_image_description(
|
||||||
|
|
||||||
struct wlr_color_management_surface_feedback_v1 *surface_feedback;
|
struct wlr_color_management_surface_feedback_v1 *surface_feedback;
|
||||||
wl_list_for_each(surface_feedback, &manager->surface_feedbacks, link) {
|
wl_list_for_each(surface_feedback, &manager->surface_feedbacks, link) {
|
||||||
if (surface_feedback->surface == surface) {
|
if (surface_feedback->surface != surface ||
|
||||||
surface_feedback->data = *data;
|
img_desc_data_equal(&surface_feedback->data, data)) {
|
||||||
uint32_t version = wl_resource_get_version(surface_feedback->resource);
|
continue;
|
||||||
if (version >= WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_PREFERRED_CHANGED2_SINCE_VERSION) {
|
}
|
||||||
wp_color_management_surface_feedback_v1_send_preferred_changed2(
|
|
||||||
surface_feedback->resource, identity_hi, identity_lo);
|
surface_feedback->data = *data;
|
||||||
} else {
|
|
||||||
wp_color_management_surface_feedback_v1_send_preferred_changed(
|
uint32_t version = wl_resource_get_version(surface_feedback->resource);
|
||||||
surface_feedback->resource, identity_lo);
|
if (version >= WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_PREFERRED_CHANGED2_SINCE_VERSION) {
|
||||||
}
|
wp_color_management_surface_feedback_v1_send_preferred_changed2(
|
||||||
|
surface_feedback->resource, identity_hi, identity_lo);
|
||||||
|
} else {
|
||||||
|
wp_color_management_surface_feedback_v1_send_preferred_changed(
|
||||||
|
surface_feedback->resource, identity_lo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -518,14 +518,16 @@ static void cursor_session_handle_get_capture_session(struct wl_client *client,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor_session->capture_session_created = true;
|
struct wlr_ext_image_copy_capture_manager_v1 *manager = NULL;
|
||||||
|
|
||||||
struct wlr_ext_image_capture_source_v1 *source = NULL;
|
struct wlr_ext_image_capture_source_v1 *source = NULL;
|
||||||
|
|
||||||
if (cursor_session != NULL) {
|
if (cursor_session != NULL) {
|
||||||
|
manager = cursor_session->manager;
|
||||||
|
cursor_session->capture_session_created = true;
|
||||||
source = &cursor_session->source->base;
|
source = &cursor_session->source->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
session_create(cursor_session_resource, new_id, source, 0, cursor_session->manager);
|
session_create(cursor_session_resource, new_id, source, 0, manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ext_image_copy_capture_cursor_session_v1_interface cursor_session_impl = {
|
static const struct ext_image_copy_capture_cursor_session_v1_interface cursor_session_impl = {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/render/drm_syncobj.h>
|
#include <wlr/render/drm_syncobj.h>
|
||||||
#include <wlr/types/wlr_buffer.h>
|
#include <wlr/types/wlr_buffer.h>
|
||||||
#include <wlr/types/wlr_compositor.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
|
|
@ -11,6 +12,7 @@
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "linux-drm-syncobj-v1-protocol.h"
|
#include "linux-drm-syncobj-v1-protocol.h"
|
||||||
|
#include "render/drm_syncobj_merger.h"
|
||||||
|
|
||||||
#define LINUX_DRM_SYNCOBJ_V1_VERSION 1
|
#define LINUX_DRM_SYNCOBJ_V1_VERSION 1
|
||||||
|
|
||||||
|
|
@ -158,20 +160,39 @@ static void surface_synced_finish_state(void *_state) {
|
||||||
struct wlr_linux_drm_syncobj_surface_v1_state *state = _state;
|
struct wlr_linux_drm_syncobj_surface_v1_state *state = _state;
|
||||||
wlr_drm_syncobj_timeline_unref(state->acquire_timeline);
|
wlr_drm_syncobj_timeline_unref(state->acquire_timeline);
|
||||||
wlr_drm_syncobj_timeline_unref(state->release_timeline);
|
wlr_drm_syncobj_timeline_unref(state->release_timeline);
|
||||||
|
wlr_drm_syncobj_merger_unref(state->release_merger);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void surface_synced_move_state(void *_dst, void *_src) {
|
static void surface_synced_move_state(void *_dst, void *_src) {
|
||||||
struct wlr_linux_drm_syncobj_surface_v1_state *dst = _dst, *src = _src;
|
struct wlr_linux_drm_syncobj_surface_v1_state *dst = _dst, *src = _src;
|
||||||
// TODO: immediately signal dst.release_timeline if necessary
|
if (src->acquire_timeline == NULL) {
|
||||||
|
// ignore commits that did not attach a buffer
|
||||||
|
return;
|
||||||
|
}
|
||||||
surface_synced_finish_state(dst);
|
surface_synced_finish_state(dst);
|
||||||
*dst = *src;
|
*dst = *src;
|
||||||
|
dst->committed = true;
|
||||||
*src = (struct wlr_linux_drm_syncobj_surface_v1_state){0};
|
*src = (struct wlr_linux_drm_syncobj_surface_v1_state){0};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void surface_synced_commit(struct wlr_surface_synced *synced) {
|
||||||
|
struct wlr_linux_drm_syncobj_surface_v1 *surface = wl_container_of(synced, surface, synced);
|
||||||
|
|
||||||
|
if (!surface->current.committed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
surface->current.release_merger = wlr_drm_syncobj_merger_create(
|
||||||
|
surface->current.release_timeline, surface->current.release_point);
|
||||||
|
surface->current.committed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const struct wlr_surface_synced_impl surface_synced_impl = {
|
static const struct wlr_surface_synced_impl surface_synced_impl = {
|
||||||
.state_size = sizeof(struct wlr_linux_drm_syncobj_surface_v1_state),
|
.state_size = sizeof(struct wlr_linux_drm_syncobj_surface_v1_state),
|
||||||
.finish_state = surface_synced_finish_state,
|
.finish_state = surface_synced_finish_state,
|
||||||
.move_state = surface_synced_move_state,
|
.move_state = surface_synced_move_state,
|
||||||
|
.commit = surface_synced_commit,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void manager_handle_destroy(struct wl_client *client,
|
static void manager_handle_destroy(struct wl_client *client,
|
||||||
|
|
@ -422,6 +443,11 @@ struct wlr_linux_drm_syncobj_manager_v1 *wlr_linux_drm_syncobj_manager_v1_create
|
||||||
struct wl_display *display, uint32_t version, int drm_fd) {
|
struct wl_display *display, uint32_t version, int drm_fd) {
|
||||||
assert(version <= LINUX_DRM_SYNCOBJ_V1_VERSION);
|
assert(version <= LINUX_DRM_SYNCOBJ_V1_VERSION);
|
||||||
|
|
||||||
|
if (!HAVE_LINUX_SYNC_FILE) {
|
||||||
|
wlr_log(WLR_INFO, "Linux sync_file unavailable, disabling linux-drm-syncobj-v1");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!check_syncobj_eventfd(drm_fd)) {
|
if (!check_syncobj_eventfd(drm_fd)) {
|
||||||
wlr_log(WLR_INFO, "DRM syncobj eventfd unavailable, disabling linux-drm-syncobj-v1");
|
wlr_log(WLR_INFO, "DRM syncobj eventfd unavailable, disabling linux-drm-syncobj-v1");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -467,20 +493,14 @@ wlr_linux_drm_syncobj_v1_get_surface_state(struct wlr_surface *wlr_surface) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct release_signaller {
|
struct release_signaller {
|
||||||
struct wlr_drm_syncobj_timeline *timeline;
|
struct wlr_drm_syncobj_merger *merger;
|
||||||
uint64_t point;
|
|
||||||
struct wl_listener buffer_release;
|
struct wl_listener buffer_release;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void release_signaller_handle_buffer_release(struct wl_listener *listener, void *data) {
|
static void release_signaller_handle_buffer_release(struct wl_listener *listener, void *data) {
|
||||||
struct release_signaller *signaller = wl_container_of(listener, signaller, buffer_release);
|
struct release_signaller *signaller = wl_container_of(listener, signaller, buffer_release);
|
||||||
|
|
||||||
if (drmSyncobjTimelineSignal(signaller->timeline->drm_fd, &signaller->timeline->handle,
|
wlr_drm_syncobj_merger_unref(signaller->merger);
|
||||||
&signaller->point, 1) != 0) {
|
|
||||||
wlr_log(WLR_ERROR, "drmSyncobjTimelineSignal() failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_drm_syncobj_timeline_unref(signaller->timeline);
|
|
||||||
wl_list_remove(&signaller->buffer_release.link);
|
wl_list_remove(&signaller->buffer_release.link);
|
||||||
free(signaller);
|
free(signaller);
|
||||||
}
|
}
|
||||||
|
|
@ -488,7 +508,7 @@ static void release_signaller_handle_buffer_release(struct wl_listener *listener
|
||||||
bool wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(
|
bool wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(
|
||||||
struct wlr_linux_drm_syncobj_surface_v1_state *state, struct wlr_buffer *buffer) {
|
struct wlr_linux_drm_syncobj_surface_v1_state *state, struct wlr_buffer *buffer) {
|
||||||
assert(buffer->n_locks > 0);
|
assert(buffer->n_locks > 0);
|
||||||
if (state->release_timeline == NULL) {
|
if (state->release_merger == NULL) {
|
||||||
// This can happen if an existing surface with a buffer has a
|
// This can happen if an existing surface with a buffer has a
|
||||||
// syncobj_surface_v1_state created but no new buffer with release
|
// syncobj_surface_v1_state created but no new buffer with release
|
||||||
// timeline committed.
|
// timeline committed.
|
||||||
|
|
@ -500,11 +520,23 @@ bool wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
signaller->timeline = wlr_drm_syncobj_timeline_ref(state->release_timeline);
|
signaller->merger = wlr_drm_syncobj_merger_ref(state->release_merger);
|
||||||
signaller->point = state->release_point;
|
|
||||||
|
|
||||||
signaller->buffer_release.notify = release_signaller_handle_buffer_release;
|
signaller->buffer_release.notify = release_signaller_handle_buffer_release;
|
||||||
wl_signal_add(&buffer->events.release, &signaller->buffer_release);
|
wl_signal_add(&buffer->events.release, &signaller->buffer_release);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wlr_linux_drm_syncobj_v1_state_add_release_point(
|
||||||
|
struct wlr_linux_drm_syncobj_surface_v1_state *state,
|
||||||
|
struct wlr_drm_syncobj_timeline *release_timeline, uint64_t release_point,
|
||||||
|
struct wl_event_loop *event_loop) {
|
||||||
|
if (state->release_merger == NULL) {
|
||||||
|
// This can happen if an existing surface with a buffer has a
|
||||||
|
// syncobj_surface_v1_state created but no new buffer with release
|
||||||
|
// timeline committed.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return wlr_drm_syncobj_merger_add(state->release_merger,
|
||||||
|
release_timeline, release_point, event_loop);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ static const struct wlr_keyboard_impl keyboard_impl = {
|
||||||
|
|
||||||
static const struct zwp_virtual_keyboard_v1_interface virtual_keyboard_impl;
|
static const struct zwp_virtual_keyboard_v1_interface virtual_keyboard_impl;
|
||||||
|
|
||||||
static struct wlr_virtual_keyboard_v1 *virtual_keyboard_from_resource(
|
struct wlr_virtual_keyboard_v1 *wlr_virtual_keyboard_v1_from_resource(
|
||||||
struct wl_resource *resource) {
|
struct wl_resource *resource) {
|
||||||
assert(wl_resource_instance_of(resource,
|
assert(wl_resource_instance_of(resource,
|
||||||
&zwp_virtual_keyboard_v1_interface, &virtual_keyboard_impl));
|
&zwp_virtual_keyboard_v1_interface, &virtual_keyboard_impl));
|
||||||
|
|
@ -39,7 +39,7 @@ static void virtual_keyboard_keymap(struct wl_client *client,
|
||||||
struct wl_resource *resource, uint32_t format, int32_t fd,
|
struct wl_resource *resource, uint32_t format, int32_t fd,
|
||||||
uint32_t size) {
|
uint32_t size) {
|
||||||
struct wlr_virtual_keyboard_v1 *keyboard =
|
struct wlr_virtual_keyboard_v1 *keyboard =
|
||||||
virtual_keyboard_from_resource(resource);
|
wlr_virtual_keyboard_v1_from_resource(resource);
|
||||||
if (keyboard == NULL) {
|
if (keyboard == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +76,7 @@ static void virtual_keyboard_key(struct wl_client *client,
|
||||||
struct wl_resource *resource, uint32_t time, uint32_t key,
|
struct wl_resource *resource, uint32_t time, uint32_t key,
|
||||||
uint32_t state) {
|
uint32_t state) {
|
||||||
struct wlr_virtual_keyboard_v1 *keyboard =
|
struct wlr_virtual_keyboard_v1 *keyboard =
|
||||||
virtual_keyboard_from_resource(resource);
|
wlr_virtual_keyboard_v1_from_resource(resource);
|
||||||
if (keyboard == NULL) {
|
if (keyboard == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -99,7 +99,7 @@ static void virtual_keyboard_modifiers(struct wl_client *client,
|
||||||
struct wl_resource *resource, uint32_t mods_depressed,
|
struct wl_resource *resource, uint32_t mods_depressed,
|
||||||
uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {
|
uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {
|
||||||
struct wlr_virtual_keyboard_v1 *keyboard =
|
struct wlr_virtual_keyboard_v1 *keyboard =
|
||||||
virtual_keyboard_from_resource(resource);
|
wlr_virtual_keyboard_v1_from_resource(resource);
|
||||||
if (keyboard == NULL) {
|
if (keyboard == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -113,21 +113,24 @@ static void virtual_keyboard_modifiers(struct wl_client *client,
|
||||||
mods_depressed, mods_latched, mods_locked, group);
|
mods_depressed, mods_latched, mods_locked, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtual_keyboard_destroy_resource(struct wl_resource *resource) {
|
static void virtual_keyboard_destroy(struct wlr_virtual_keyboard_v1 *virtual_keyboard) {
|
||||||
struct wlr_virtual_keyboard_v1 *keyboard =
|
wlr_keyboard_finish(&virtual_keyboard->keyboard);
|
||||||
virtual_keyboard_from_resource(resource);
|
wl_resource_set_user_data(virtual_keyboard->resource, NULL);
|
||||||
if (keyboard == NULL) {
|
wl_list_remove(&virtual_keyboard->seat_destroy.link);
|
||||||
return;
|
wl_list_remove(&virtual_keyboard->link);
|
||||||
}
|
free(virtual_keyboard);
|
||||||
|
|
||||||
wlr_keyboard_finish(&keyboard->keyboard);
|
|
||||||
|
|
||||||
wl_resource_set_user_data(keyboard->resource, NULL);
|
|
||||||
wl_list_remove(&keyboard->link);
|
|
||||||
free(keyboard);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtual_keyboard_destroy(struct wl_client *client,
|
static void virtual_keyboard_destroy_resource(struct wl_resource *resource) {
|
||||||
|
struct wlr_virtual_keyboard_v1 *virtual_keyboard =
|
||||||
|
wlr_virtual_keyboard_v1_from_resource(resource);
|
||||||
|
if (virtual_keyboard == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
virtual_keyboard_destroy(virtual_keyboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtual_keyboard_handle_destroy(struct wl_client *client,
|
||||||
struct wl_resource *resource) {
|
struct wl_resource *resource) {
|
||||||
wl_resource_destroy(resource);
|
wl_resource_destroy(resource);
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +139,7 @@ static const struct zwp_virtual_keyboard_v1_interface virtual_keyboard_impl = {
|
||||||
.keymap = virtual_keyboard_keymap,
|
.keymap = virtual_keyboard_keymap,
|
||||||
.key = virtual_keyboard_key,
|
.key = virtual_keyboard_key,
|
||||||
.modifiers = virtual_keyboard_modifiers,
|
.modifiers = virtual_keyboard_modifiers,
|
||||||
.destroy = virtual_keyboard_destroy,
|
.destroy = virtual_keyboard_handle_destroy,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct zwp_virtual_keyboard_manager_v1_interface manager_impl;
|
static const struct zwp_virtual_keyboard_manager_v1_interface manager_impl;
|
||||||
|
|
@ -148,6 +151,13 @@ static struct wlr_virtual_keyboard_manager_v1 *manager_from_resource(
|
||||||
return wl_resource_get_user_data(resource);
|
return wl_resource_get_user_data(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void virtual_keyboard_handle_seat_destroy(struct wl_listener *listener,
|
||||||
|
void *data) {
|
||||||
|
struct wlr_virtual_keyboard_v1 *virtual_keyboard = wl_container_of(listener, virtual_keyboard,
|
||||||
|
seat_destroy);
|
||||||
|
virtual_keyboard_destroy(virtual_keyboard);
|
||||||
|
}
|
||||||
|
|
||||||
static void virtual_keyboard_manager_create_virtual_keyboard(
|
static void virtual_keyboard_manager_create_virtual_keyboard(
|
||||||
struct wl_client *client, struct wl_resource *resource,
|
struct wl_client *client, struct wl_resource *resource,
|
||||||
struct wl_resource *seat, uint32_t id) {
|
struct wl_resource *seat, uint32_t id) {
|
||||||
|
|
@ -181,6 +191,9 @@ static void virtual_keyboard_manager_create_virtual_keyboard(
|
||||||
virtual_keyboard->seat = seat_client->seat;
|
virtual_keyboard->seat = seat_client->seat;
|
||||||
wl_resource_set_user_data(keyboard_resource, virtual_keyboard);
|
wl_resource_set_user_data(keyboard_resource, virtual_keyboard);
|
||||||
|
|
||||||
|
wl_signal_add(&seat_client->events.destroy, &virtual_keyboard->seat_destroy);
|
||||||
|
virtual_keyboard->seat_destroy.notify = virtual_keyboard_handle_seat_destroy;
|
||||||
|
|
||||||
wl_list_insert(&manager->virtual_keyboards, &virtual_keyboard->link);
|
wl_list_insert(&manager->virtual_keyboards, &virtual_keyboard->link);
|
||||||
|
|
||||||
wl_signal_emit_mutable(&manager->events.new_virtual_keyboard,
|
wl_signal_emit_mutable(&manager->events.new_virtual_keyboard,
|
||||||
|
|
|
||||||
16
util/box.c
16
util/box.c
|
|
@ -4,6 +4,14 @@
|
||||||
#include <wlr/util/box.h>
|
#include <wlr/util/box.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
static int max(int a, int b) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int min(int a, int b) {
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
void wlr_box_closest_point(const struct wlr_box *box, double x, double y,
|
void wlr_box_closest_point(const struct wlr_box *box, double x, double y,
|
||||||
double *dest_x, double *dest_y) {
|
double *dest_x, double *dest_y) {
|
||||||
// if box is empty, then it contains no points, so no closest point either
|
// if box is empty, then it contains no points, so no closest point either
|
||||||
|
|
@ -56,10 +64,10 @@ bool wlr_box_intersection(struct wlr_box *dest, const struct wlr_box *box_a,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int x1 = fmax(box_a->x, box_b->x);
|
int x1 = max(box_a->x, box_b->x);
|
||||||
int y1 = fmax(box_a->y, box_b->y);
|
int y1 = max(box_a->y, box_b->y);
|
||||||
int x2 = fmin(box_a->x + box_a->width, box_b->x + box_b->width);
|
int x2 = min(box_a->x + box_a->width, box_b->x + box_b->width);
|
||||||
int y2 = fmin(box_a->y + box_a->height, box_b->y + box_b->height);
|
int y2 = min(box_a->y + box_a->height, box_b->y + box_b->height);
|
||||||
|
|
||||||
dest->x = x1;
|
dest->x = x1;
|
||||||
dest->y = y1;
|
dest->y = y1;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue