mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-03-31 07:11:32 -04:00
Compare commits
39 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e22084f639 | ||
|
|
334019f839 | ||
|
|
a1ed6fca52 | ||
|
|
f295d0322a | ||
|
|
413664e0b0 | ||
|
|
fd870f6d27 | ||
|
|
4ca40004fd | ||
|
|
7287f700ab | ||
|
|
8fe3034948 | ||
|
|
627da39e76 | ||
|
|
8d454e1e34 | ||
|
|
cd555f9261 | ||
|
|
b2f6a390a4 | ||
|
|
bfd6e619fc | ||
|
|
e83a679e23 | ||
|
|
1f3d351abb | ||
|
|
0af9b9d003 | ||
|
|
abb6eeb422 | ||
|
|
dca0703dac | ||
|
|
80bcef908b | ||
|
|
58c158dba6 | ||
|
|
1fa8bb8f7a | ||
|
|
ec746d3e3e | ||
|
|
1fc928d528 | ||
|
|
3cb2cf9425 | ||
|
|
7f87c7fe90 | ||
|
|
39e918edc8 | ||
|
|
736c0f3f25 | ||
|
|
3c8d199ec1 | ||
|
|
7ccef7d9eb | ||
|
|
2938c10cd3 | ||
|
|
648790f43a | ||
|
|
ff7d093800 | ||
|
|
285cee5f3a | ||
|
|
9a931d9ffa | ||
|
|
3dafaa4df3 | ||
|
|
67ce318b1f | ||
|
|
14b3c96c1e | ||
|
|
3336d28813 |
70 changed files with 1182 additions and 343 deletions
|
|
@ -35,6 +35,9 @@ tasks:
|
||||||
cd wlroots
|
cd wlroots
|
||||||
ninja -C build
|
ninja -C build
|
||||||
sudo ninja -C build install
|
sudo ninja -C build install
|
||||||
|
- test: |
|
||||||
|
cd wlroots
|
||||||
|
meson test -C build --verbose
|
||||||
- build-features-disabled: |
|
- build-features-disabled: |
|
||||||
cd wlroots
|
cd wlroots
|
||||||
meson setup build --reconfigure -Dauto_features=disabled
|
meson setup build --reconfigure -Dauto_features=disabled
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,10 @@ tasks:
|
||||||
- clang: |
|
- clang: |
|
||||||
cd wlroots/build-clang
|
cd wlroots/build-clang
|
||||||
ninja
|
ninja
|
||||||
|
- test: |
|
||||||
|
cd wlroots/build-gcc
|
||||||
|
meson test --verbose
|
||||||
|
meson test --benchmark --verbose
|
||||||
- smoke-test: |
|
- smoke-test: |
|
||||||
cd wlroots/build-gcc/tinywl
|
cd wlroots/build-gcc/tinywl
|
||||||
sudo modprobe vkms
|
sudo modprobe vkms
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,9 @@ tasks:
|
||||||
meson setup build --fatal-meson-warnings -Dauto_features=enabled -Dallocators=gbm
|
meson setup build --fatal-meson-warnings -Dauto_features=enabled -Dallocators=gbm
|
||||||
ninja -C build
|
ninja -C build
|
||||||
sudo ninja -C build install
|
sudo ninja -C build install
|
||||||
|
- test: |
|
||||||
|
cd wlroots
|
||||||
|
meson test -C build --verbose
|
||||||
- tinywl: |
|
- tinywl: |
|
||||||
cd wlroots/tinywl
|
cd wlroots/tinywl
|
||||||
make
|
make
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <assert.h>
|
||||||
#include <drm_fourcc.h>
|
#include <drm_fourcc.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -423,12 +424,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 +441,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) {
|
||||||
|
|
@ -484,6 +476,62 @@ static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm,
|
||||||
atomic_add(atom, id, props->crtc_h, dst_box->height);
|
atomic_add(atom, id, props->crtc_h, dst_box->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_color_encoding_and_range(struct atomic *atom,
|
||||||
|
struct wlr_drm_backend *drm, struct wlr_drm_plane *plane,
|
||||||
|
enum wlr_color_encoding encoding, enum wlr_color_range range) {
|
||||||
|
uint32_t id = plane->id;
|
||||||
|
const struct wlr_drm_plane_props *props = &plane->props;
|
||||||
|
|
||||||
|
uint32_t color_encoding;
|
||||||
|
switch (encoding) {
|
||||||
|
case WLR_COLOR_ENCODING_NONE:
|
||||||
|
case WLR_COLOR_ENCODING_BT601:
|
||||||
|
color_encoding = WLR_DRM_COLOR_YCBCR_BT601;
|
||||||
|
break;
|
||||||
|
case WLR_COLOR_ENCODING_BT709:
|
||||||
|
color_encoding = WLR_DRM_COLOR_YCBCR_BT709;
|
||||||
|
break;
|
||||||
|
case WLR_COLOR_ENCODING_BT2020:
|
||||||
|
color_encoding = WLR_DRM_COLOR_YCBCR_BT2020;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
wlr_log(WLR_DEBUG, "Unsupported color encoding %d", encoding);
|
||||||
|
atom->failed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props->color_encoding) {
|
||||||
|
atomic_add(atom, id, props->color_encoding, color_encoding);
|
||||||
|
} else {
|
||||||
|
wlr_log(WLR_DEBUG, "Plane %"PRIu32" is missing the COLOR_ENCODING property",
|
||||||
|
id);
|
||||||
|
atom->failed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t color_range;
|
||||||
|
switch (range) {
|
||||||
|
case WLR_COLOR_RANGE_NONE:
|
||||||
|
case WLR_COLOR_RANGE_LIMITED:
|
||||||
|
color_range = WLR_DRM_COLOR_YCBCR_LIMITED_RANGE;
|
||||||
|
break;
|
||||||
|
case WLR_COLOR_RANGE_FULL:
|
||||||
|
color_range = WLR_DRM_COLOR_YCBCR_FULL_RANGE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0); // Unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props->color_range) {
|
||||||
|
atomic_add(atom, id, props->color_range, color_range);
|
||||||
|
} else {
|
||||||
|
wlr_log(WLR_DEBUG, "Plane %"PRIu32" is missing the COLOR_RANGE property",
|
||||||
|
id);
|
||||||
|
atom->failed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool supports_cursor_hotspots(const struct wlr_drm_plane *plane) {
|
static bool supports_cursor_hotspots(const struct wlr_drm_plane *plane) {
|
||||||
return plane->props.hotspot_x && plane->props.hotspot_y;
|
return plane->props.hotspot_x && plane->props.hotspot_y;
|
||||||
}
|
}
|
||||||
|
|
@ -500,19 +548,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;
|
||||||
|
|
@ -550,6 +585,10 @@ static void atomic_connector_add(struct atomic *atom,
|
||||||
|
|
||||||
set_plane_props(atom, drm, crtc->primary, state->primary_fb, crtc->id,
|
set_plane_props(atom, drm, crtc->primary, state->primary_fb, crtc->id,
|
||||||
&state->primary_viewport.dst_box, &state->primary_viewport.src_box);
|
&state->primary_viewport.dst_box, &state->primary_viewport.src_box);
|
||||||
|
if (state->base->committed & WLR_OUTPUT_STATE_COLOR_REPRESENTATION) {
|
||||||
|
set_color_encoding_and_range(atom, drm, crtc->primary,
|
||||||
|
state->base->color_encoding, state->base->color_range);
|
||||||
|
}
|
||||||
if (crtc->primary->props.fb_damage_clips != 0) {
|
if (crtc->primary->props.fb_damage_clips != 0) {
|
||||||
atomic_add(atom, crtc->primary->id,
|
atomic_add(atom, crtc->primary->id,
|
||||||
crtc->primary->props.fb_damage_clips, state->fb_damage_clips);
|
crtc->primary->props.fb_damage_clips, state->fb_damage_clips);
|
||||||
|
|
@ -557,9 +596,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 = {
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ static const struct wlr_backend_impl backend_impl = {
|
||||||
.commit = backend_commit,
|
.commit = backend_commit,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool wlr_backend_is_drm(struct wlr_backend *b) {
|
bool wlr_backend_is_drm(const struct wlr_backend *b) {
|
||||||
return b->impl == &backend_impl;
|
return b->impl == &backend_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,8 @@ static const uint32_t COMMIT_OUTPUT_STATE =
|
||||||
WLR_OUTPUT_STATE_WAIT_TIMELINE |
|
WLR_OUTPUT_STATE_WAIT_TIMELINE |
|
||||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
|
WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
|
||||||
WLR_OUTPUT_STATE_COLOR_TRANSFORM |
|
WLR_OUTPUT_STATE_COLOR_TRANSFORM |
|
||||||
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION;
|
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION |
|
||||||
|
WLR_OUTPUT_STATE_COLOR_REPRESENTATION;
|
||||||
|
|
||||||
static const uint32_t SUPPORTED_OUTPUT_STATE =
|
static const uint32_t SUPPORTED_OUTPUT_STATE =
|
||||||
WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE;
|
WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE;
|
||||||
|
|
@ -367,7 +368,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 +567,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 +669,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;
|
||||||
|
|
@ -1299,7 +1321,7 @@ static const struct wlr_output_impl output_impl = {
|
||||||
.get_primary_formats = drm_connector_get_primary_formats,
|
.get_primary_formats = drm_connector_get_primary_formats,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool wlr_output_is_drm(struct wlr_output *output) {
|
bool wlr_output_is_drm(const struct wlr_output *output) {
|
||||||
return output->impl == &output_impl;
|
return output->impl == &output_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2018,6 +2040,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++) {
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,8 @@ static const struct prop_info crtc_info[] = {
|
||||||
|
|
||||||
static const struct prop_info plane_info[] = {
|
static const struct prop_info plane_info[] = {
|
||||||
#define INDEX(name) (offsetof(struct wlr_drm_plane_props, name) / sizeof(uint32_t))
|
#define INDEX(name) (offsetof(struct wlr_drm_plane_props, name) / sizeof(uint32_t))
|
||||||
|
{ "COLOR_ENCODING", INDEX(color_encoding) },
|
||||||
|
{ "COLOR_RANGE", INDEX(color_range) },
|
||||||
{ "CRTC_H", INDEX(crtc_h) },
|
{ "CRTC_H", INDEX(crtc_h) },
|
||||||
{ "CRTC_ID", INDEX(crtc_id) },
|
{ "CRTC_ID", INDEX(crtc_id) },
|
||||||
{ "CRTC_W", INDEX(crtc_w) },
|
{ "CRTC_W", INDEX(crtc_w) },
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,6 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_event_loop *loop) {
|
||||||
return &backend->backend;
|
return &backend->backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wlr_backend_is_headless(struct wlr_backend *backend) {
|
bool wlr_backend_is_headless(const struct wlr_backend *backend) {
|
||||||
return backend->impl == &backend_impl;
|
return backend->impl == &backend_impl;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ static const struct wlr_output_impl output_impl = {
|
||||||
.move_cursor = output_move_cursor,
|
.move_cursor = output_move_cursor,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool wlr_output_is_headless(struct wlr_output *wlr_output) {
|
bool wlr_output_is_headless(const struct wlr_output *wlr_output) {
|
||||||
return wlr_output->impl == &output_impl;
|
return wlr_output->impl == &output_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@ static const struct wlr_backend_impl backend_impl = {
|
||||||
.destroy = backend_destroy,
|
.destroy = backend_destroy,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool wlr_backend_is_libinput(struct wlr_backend *b) {
|
bool wlr_backend_is_libinput(const struct wlr_backend *b) {
|
||||||
return b->impl == &backend_impl;
|
return b->impl == &backend_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ struct wlr_backend *wlr_multi_backend_create(struct wl_event_loop *loop) {
|
||||||
return &backend->backend;
|
return &backend->backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wlr_backend_is_multi(struct wlr_backend *b) {
|
bool wlr_backend_is_multi(const struct wlr_backend *b) {
|
||||||
return b->impl == &backend_impl;
|
return b->impl == &backend_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -577,7 +577,7 @@ static const struct wlr_backend_impl backend_impl = {
|
||||||
.get_drm_fd = backend_get_drm_fd,
|
.get_drm_fd = backend_get_drm_fd,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool wlr_backend_is_wl(struct wlr_backend *b) {
|
bool wlr_backend_is_wl(const struct wlr_backend *b) {
|
||||||
return b->impl == &backend_impl;
|
return b->impl == &backend_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1027,7 +1027,7 @@ static const struct wlr_output_impl output_impl = {
|
||||||
.get_primary_formats = output_get_formats,
|
.get_primary_formats = output_get_formats,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool wlr_output_is_wl(struct wlr_output *wlr_output) {
|
bool wlr_output_is_wl(const struct wlr_output *wlr_output) {
|
||||||
return wlr_output->impl == &output_impl;
|
return wlr_output->impl == &output_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -218,7 +219,7 @@ static const struct wlr_backend_impl backend_impl = {
|
||||||
.get_drm_fd = backend_get_drm_fd,
|
.get_drm_fd = backend_get_drm_fd,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool wlr_backend_is_x11(struct wlr_backend *backend) {
|
bool wlr_backend_is_x11(const struct wlr_backend *backend) {
|
||||||
return backend->impl == &backend_impl;
|
return backend->impl == &backend_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -711,7 +711,7 @@ void handle_x11_configure_notify(struct wlr_x11_output *output,
|
||||||
wlr_output_state_finish(&state);
|
wlr_output_state_finish(&state);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wlr_output_is_x11(struct wlr_output *wlr_output) {
|
bool wlr_output_is_x11(const struct wlr_output *wlr_output) {
|
||||||
return wlr_output->impl == &output_impl;
|
return wlr_output->impl == &output_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,22 @@ struct wlr_drm_plane_props {
|
||||||
uint32_t hotspot_x;
|
uint32_t hotspot_x;
|
||||||
uint32_t hotspot_y;
|
uint32_t hotspot_y;
|
||||||
uint32_t in_fence_fd;
|
uint32_t in_fence_fd;
|
||||||
|
|
||||||
|
uint32_t color_encoding; // Not guaranteed to exist
|
||||||
|
uint32_t color_range; // Not guaranteed to exist
|
||||||
|
};
|
||||||
|
|
||||||
|
// Equivalent to wlr_drm_color_encoding defined in the kernel (but not exported)
|
||||||
|
enum wlr_drm_color_encoding {
|
||||||
|
WLR_DRM_COLOR_YCBCR_BT601,
|
||||||
|
WLR_DRM_COLOR_YCBCR_BT709,
|
||||||
|
WLR_DRM_COLOR_YCBCR_BT2020,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Equivalent to wlr_drm_color_range defined in the kernel (but not exported)
|
||||||
|
enum wlr_drm_color_range {
|
||||||
|
WLR_DRM_COLOR_YCBCR_FULL_RANGE,
|
||||||
|
WLR_DRM_COLOR_YCBCR_LIMITED_RANGE,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool get_drm_connector_props(int fd, uint32_t id,
|
bool get_drm_connector_props(int fd, uint32_t id,
|
||||||
|
|
|
||||||
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
|
||||||
|
|
@ -56,6 +56,10 @@ struct wlr_vk_device {
|
||||||
PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR;
|
PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR;
|
||||||
PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR;
|
PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR;
|
||||||
PFN_vkQueueSubmit2KHR vkQueueSubmit2KHR;
|
PFN_vkQueueSubmit2KHR vkQueueSubmit2KHR;
|
||||||
|
PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR;
|
||||||
|
PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR;
|
||||||
|
PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR;
|
||||||
|
PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR;
|
||||||
} api;
|
} api;
|
||||||
|
|
||||||
uint32_t format_prop_count;
|
uint32_t format_prop_count;
|
||||||
|
|
@ -406,7 +410,7 @@ VkCommandBuffer vulkan_record_stage_cb(struct wlr_vk_renderer *renderer);
|
||||||
|
|
||||||
// Submits the current stage command buffer and waits until it has
|
// Submits the current stage command buffer and waits until it has
|
||||||
// finished execution.
|
// finished execution.
|
||||||
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer);
|
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer, int wait_sync_file_fd);
|
||||||
|
|
||||||
struct wlr_vk_render_pass_texture {
|
struct wlr_vk_render_pass_texture {
|
||||||
struct wlr_vk_texture *texture;
|
struct wlr_vk_texture *texture;
|
||||||
|
|
@ -472,6 +476,8 @@ uint64_t vulkan_end_command_buffer(struct wlr_vk_command_buffer *cb,
|
||||||
void vulkan_reset_command_buffer(struct wlr_vk_command_buffer *cb);
|
void vulkan_reset_command_buffer(struct wlr_vk_command_buffer *cb);
|
||||||
bool vulkan_wait_command_buffer(struct wlr_vk_command_buffer *cb,
|
bool vulkan_wait_command_buffer(struct wlr_vk_command_buffer *cb,
|
||||||
struct wlr_vk_renderer *renderer);
|
struct wlr_vk_renderer *renderer);
|
||||||
|
VkSemaphore vulkan_command_buffer_wait_sync_file(struct wlr_vk_renderer *renderer,
|
||||||
|
struct wlr_vk_command_buffer *render_cb, size_t sem_index, int sync_file_fd);
|
||||||
|
|
||||||
bool vulkan_sync_render_pass_release(struct wlr_vk_renderer *renderer,
|
bool vulkan_sync_render_pass_release(struct wlr_vk_renderer *renderer,
|
||||||
struct wlr_vk_render_pass *pass);
|
struct wlr_vk_render_pass *pass);
|
||||||
|
|
@ -484,7 +490,8 @@ bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,
|
||||||
VkFormat src_format, VkImage src_image,
|
VkFormat src_format, VkImage src_image,
|
||||||
uint32_t drm_format, uint32_t stride,
|
uint32_t drm_format, uint32_t stride,
|
||||||
uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y,
|
uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y,
|
||||||
uint32_t dst_x, uint32_t dst_y, void *data);
|
uint32_t dst_x, uint32_t dst_y, void *data,
|
||||||
|
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point);
|
||||||
|
|
||||||
// State (e.g. image texture) associated with a surface.
|
// State (e.g. image texture) associated with a surface.
|
||||||
struct wlr_vk_texture {
|
struct wlr_vk_texture {
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,8 @@ struct wlr_drm_lease {
|
||||||
struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
|
struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
|
||||||
struct wlr_device *dev, struct wlr_backend *parent);
|
struct wlr_device *dev, struct wlr_backend *parent);
|
||||||
|
|
||||||
bool wlr_backend_is_drm(struct wlr_backend *backend);
|
bool wlr_backend_is_drm(const struct wlr_backend *backend);
|
||||||
bool wlr_output_is_drm(struct wlr_output *output);
|
bool wlr_output_is_drm(const struct wlr_output *output);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the parent DRM backend, if any.
|
* Get the parent DRM backend, if any.
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_event_loop *loop);
|
||||||
struct wlr_output *wlr_headless_add_output(struct wlr_backend *backend,
|
struct wlr_output *wlr_headless_add_output(struct wlr_backend *backend,
|
||||||
unsigned int width, unsigned int height);
|
unsigned int width, unsigned int height);
|
||||||
|
|
||||||
bool wlr_backend_is_headless(struct wlr_backend *backend);
|
bool wlr_backend_is_headless(const struct wlr_backend *backend);
|
||||||
bool wlr_output_is_headless(struct wlr_output *output);
|
bool wlr_output_is_headless(const struct wlr_output *output);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ struct libinput_device *wlr_libinput_get_device_handle(
|
||||||
struct libinput_tablet_tool *wlr_libinput_get_tablet_tool_handle(
|
struct libinput_tablet_tool *wlr_libinput_get_tablet_tool_handle(
|
||||||
struct wlr_tablet_tool *wlr_tablet_tool);
|
struct wlr_tablet_tool *wlr_tablet_tool);
|
||||||
|
|
||||||
bool wlr_backend_is_libinput(struct wlr_backend *backend);
|
bool wlr_backend_is_libinput(const struct wlr_backend *backend);
|
||||||
bool wlr_input_device_is_libinput(struct wlr_input_device *device);
|
bool wlr_input_device_is_libinput(struct wlr_input_device *device);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ bool wlr_multi_backend_add(struct wlr_backend *multi,
|
||||||
void wlr_multi_backend_remove(struct wlr_backend *multi,
|
void wlr_multi_backend_remove(struct wlr_backend *multi,
|
||||||
struct wlr_backend *backend);
|
struct wlr_backend *backend);
|
||||||
|
|
||||||
bool wlr_backend_is_multi(struct wlr_backend *backend);
|
bool wlr_backend_is_multi(const struct wlr_backend *backend);
|
||||||
bool wlr_multi_is_empty(struct wlr_backend *backend);
|
bool wlr_multi_is_empty(struct wlr_backend *backend);
|
||||||
|
|
||||||
void wlr_multi_for_each_backend(struct wlr_backend *backend,
|
void wlr_multi_for_each_backend(struct wlr_backend *backend,
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ struct wlr_output *wlr_wl_output_create_from_surface(struct wlr_backend *backend
|
||||||
/**
|
/**
|
||||||
* Check whether the provided backend is a Wayland backend.
|
* Check whether the provided backend is a Wayland backend.
|
||||||
*/
|
*/
|
||||||
bool wlr_backend_is_wl(struct wlr_backend *backend);
|
bool wlr_backend_is_wl(const struct wlr_backend *backend);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the provided input device is a Wayland input device.
|
* Check whether the provided input device is a Wayland input device.
|
||||||
|
|
@ -56,7 +56,7 @@ bool wlr_input_device_is_wl(struct wlr_input_device *device);
|
||||||
/**
|
/**
|
||||||
* Check whether the provided output device is a Wayland output device.
|
* Check whether the provided output device is a Wayland output device.
|
||||||
*/
|
*/
|
||||||
bool wlr_output_is_wl(struct wlr_output *output);
|
bool wlr_output_is_wl(const struct wlr_output *output);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the title of a struct wlr_output which is a Wayland toplevel.
|
* Sets the title of a struct wlr_output which is a Wayland toplevel.
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend);
|
||||||
/**
|
/**
|
||||||
* Check whether this backend is an X11 backend.
|
* Check whether this backend is an X11 backend.
|
||||||
*/
|
*/
|
||||||
bool wlr_backend_is_x11(struct wlr_backend *backend);
|
bool wlr_backend_is_x11(const struct wlr_backend *backend);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether this input device is an X11 input device.
|
* Check whether this input device is an X11 input device.
|
||||||
|
|
@ -41,7 +41,7 @@ bool wlr_input_device_is_x11(struct wlr_input_device *device);
|
||||||
/**
|
/**
|
||||||
* Check whether this output device is an X11 output device.
|
* Check whether this output device is an X11 output device.
|
||||||
*/
|
*/
|
||||||
bool wlr_output_is_x11(struct wlr_output *output);
|
bool wlr_output_is_x11(const struct wlr_output *output);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the title of a struct wlr_output which is an X11 window.
|
* Sets the title of a struct wlr_output which is an X11 window.
|
||||||
|
|
|
||||||
|
|
@ -90,10 +90,18 @@ 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.
|
||||||
*
|
*
|
||||||
* See wlr_drm_syncobj_timeline_check() for a definition of flags.
|
* Flags can be:
|
||||||
|
*
|
||||||
|
* - 0 to wait for the point to be signalled
|
||||||
|
* - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE to only wait for a fence to
|
||||||
|
* materialize
|
||||||
*
|
*
|
||||||
* A callback must be provided that will be invoked when the waiter has finished.
|
* A callback must be provided that will be invoked when the waiter has finished.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,9 @@ struct wlr_gles2_texture_attribs {
|
||||||
bool has_alpha;
|
bool has_alpha;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool wlr_renderer_is_gles2(struct wlr_renderer *wlr_renderer);
|
bool wlr_renderer_is_gles2(const struct wlr_renderer *wlr_renderer);
|
||||||
bool wlr_render_timer_is_gles2(struct wlr_render_timer *timer);
|
bool wlr_render_timer_is_gles2(const struct wlr_render_timer *timer);
|
||||||
bool wlr_texture_is_gles2(struct wlr_texture *texture);
|
bool wlr_texture_is_gles2(const struct wlr_texture *texture);
|
||||||
void wlr_gles2_texture_get_attribs(struct wlr_texture *texture,
|
void wlr_gles2_texture_get_attribs(struct wlr_texture *texture,
|
||||||
struct wlr_gles2_texture_attribs *attribs);
|
struct wlr_gles2_texture_attribs *attribs);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
struct wlr_renderer *wlr_pixman_renderer_create(void);
|
struct wlr_renderer *wlr_pixman_renderer_create(void);
|
||||||
|
|
||||||
bool wlr_renderer_is_pixman(struct wlr_renderer *wlr_renderer);
|
bool wlr_renderer_is_pixman(const struct wlr_renderer *wlr_renderer);
|
||||||
bool wlr_texture_is_pixman(struct wlr_texture *texture);
|
bool wlr_texture_is_pixman(const struct wlr_texture *texture);
|
||||||
|
|
||||||
pixman_image_t *wlr_pixman_renderer_get_buffer_image(
|
pixman_image_t *wlr_pixman_renderer_get_buffer_image(
|
||||||
struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer);
|
struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer);
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ VkPhysicalDevice wlr_vk_renderer_get_physical_device(struct wlr_renderer *render
|
||||||
VkDevice wlr_vk_renderer_get_device(struct wlr_renderer *renderer);
|
VkDevice wlr_vk_renderer_get_device(struct wlr_renderer *renderer);
|
||||||
uint32_t wlr_vk_renderer_get_queue_family(struct wlr_renderer *renderer);
|
uint32_t wlr_vk_renderer_get_queue_family(struct wlr_renderer *renderer);
|
||||||
|
|
||||||
bool wlr_renderer_is_vk(struct wlr_renderer *wlr_renderer);
|
bool wlr_renderer_is_vk(const struct wlr_renderer *wlr_renderer);
|
||||||
bool wlr_texture_is_vk(struct wlr_texture *texture);
|
bool wlr_texture_is_vk(const struct wlr_texture *texture);
|
||||||
|
|
||||||
void wlr_vk_texture_get_image_attribs(struct wlr_texture *texture,
|
void wlr_vk_texture_get_image_attribs(struct wlr_texture *texture,
|
||||||
struct wlr_vk_image_attribs *attribs);
|
struct wlr_vk_image_attribs *attribs);
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@ struct wlr_texture_read_pixels_options {
|
||||||
uint32_t dst_x, dst_y;
|
uint32_t dst_x, dst_y;
|
||||||
/** Source box of the texture to read from. If empty, the full texture is assumed. */
|
/** Source box of the texture to read from. If empty, the full texture is assumed. */
|
||||||
const struct wlr_box src_box;
|
const struct wlr_box src_box;
|
||||||
|
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||||
|
uint64_t wait_point;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool wlr_texture_read_pixels(struct wlr_texture *texture,
|
bool wlr_texture_read_pixels(struct wlr_texture *texture,
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
bool committed;
|
||||||
struct wlr_drm_syncobj_timeline *release_timeline;
|
struct wlr_drm_syncobj_timeline *release_timeline;
|
||||||
uint64_t release_point;
|
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
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ enum wlr_output_state_field {
|
||||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE = 1 << 11,
|
WLR_OUTPUT_STATE_SIGNAL_TIMELINE = 1 << 11,
|
||||||
WLR_OUTPUT_STATE_COLOR_TRANSFORM = 1 << 12,
|
WLR_OUTPUT_STATE_COLOR_TRANSFORM = 1 << 12,
|
||||||
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION = 1 << 13,
|
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION = 1 << 13,
|
||||||
|
WLR_OUTPUT_STATE_COLOR_REPRESENTATION = 1 << 14,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum wlr_output_state_mode_type {
|
enum wlr_output_state_mode_type {
|
||||||
|
|
@ -142,6 +143,10 @@ struct wlr_output_state {
|
||||||
* regular page-flip at the next wlr_output.frame event. */
|
* regular page-flip at the next wlr_output.frame event. */
|
||||||
bool tearing_page_flip;
|
bool tearing_page_flip;
|
||||||
|
|
||||||
|
// Set if (committed & WLR_OUTPUT_STATE_COLOR_REPRESENTATION)
|
||||||
|
enum wlr_color_encoding color_encoding;
|
||||||
|
enum wlr_color_range color_range;
|
||||||
|
|
||||||
enum wlr_output_state_mode_type mode_type;
|
enum wlr_output_state_mode_type mode_type;
|
||||||
struct wlr_output_mode *mode;
|
struct wlr_output_mode *mode;
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -205,6 +210,8 @@ struct wlr_output {
|
||||||
enum wl_output_transform transform;
|
enum wl_output_transform transform;
|
||||||
enum wlr_output_adaptive_sync_status adaptive_sync_status;
|
enum wlr_output_adaptive_sync_status adaptive_sync_status;
|
||||||
uint32_t render_format;
|
uint32_t render_format;
|
||||||
|
enum wlr_color_encoding color_encoding;
|
||||||
|
enum wlr_color_range color_range;
|
||||||
const struct wlr_output_image_description *image_description;
|
const struct wlr_output_image_description *image_description;
|
||||||
|
|
||||||
// Indicates whether making changes to adaptive sync status is supported.
|
// Indicates whether making changes to adaptive sync status is supported.
|
||||||
|
|
@ -625,6 +632,15 @@ void wlr_output_state_set_color_transform(struct wlr_output_state *state,
|
||||||
bool wlr_output_state_set_image_description(struct wlr_output_state *state,
|
bool wlr_output_state_set_image_description(struct wlr_output_state *state,
|
||||||
const struct wlr_output_image_description *image_desc);
|
const struct wlr_output_image_description *image_desc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the color encoding and range of the primary scanout buffer.
|
||||||
|
*
|
||||||
|
* Pass WLR_COLOR_ENCODING_NONE / WLR_COLOR_RANGE_NONE to reset to defaults.
|
||||||
|
*/
|
||||||
|
void wlr_output_state_set_color_encoding_and_range(
|
||||||
|
struct wlr_output_state *state,
|
||||||
|
enum wlr_color_encoding encoding, enum wlr_color_range range);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies the output state from src to dst. It is safe to then
|
* Copies the output state from src to dst. It is safe to then
|
||||||
* wlr_output_state_finish() src and have dst still be valid.
|
* wlr_output_state_finish() src and have dst still be valid.
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
@ -171,8 +171,6 @@ struct wlr_scene_buffer {
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct wl_signal outputs_update; // struct wlr_scene_outputs_update_event
|
struct wl_signal outputs_update; // struct wlr_scene_outputs_update_event
|
||||||
struct wl_signal output_enter; // struct wlr_scene_output
|
|
||||||
struct wl_signal output_leave; // struct wlr_scene_output
|
|
||||||
struct wl_signal output_sample; // struct wlr_scene_output_sample_event
|
struct wl_signal output_sample; // struct wlr_scene_output_sample_event
|
||||||
struct wl_signal frame_done; // struct wlr_scene_frame_done_event
|
struct wl_signal frame_done; // struct wlr_scene_frame_done_event
|
||||||
} events;
|
} events;
|
||||||
|
|
@ -268,6 +266,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
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,13 @@ void wlr_fbox_transform(struct wlr_fbox *dest, const struct wlr_fbox *box,
|
||||||
|
|
||||||
#ifdef WLR_USE_UNSTABLE
|
#ifdef WLR_USE_UNSTABLE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether two boxes intersect.
|
||||||
|
*
|
||||||
|
* Returns false if either box is empty.
|
||||||
|
*/
|
||||||
|
bool wlr_box_intersects(const struct wlr_box *a, const struct wlr_box *b);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the two boxes are equal, false otherwise.
|
* Returns true if the two boxes are equal, false otherwise.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -82,9 +82,9 @@ void xwm_handle_selection_notify(struct wlr_xwm *xwm,
|
||||||
xcb_selection_notify_event_t *event);
|
xcb_selection_notify_event_t *event);
|
||||||
int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm,
|
int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm,
|
||||||
xcb_xfixes_selection_notify_event_t *event);
|
xcb_xfixes_selection_notify_event_t *event);
|
||||||
bool data_source_is_xwayland(struct wlr_data_source *wlr_source);
|
bool data_source_is_xwayland(const struct wlr_data_source *wlr_source);
|
||||||
bool primary_selection_source_is_xwayland(
|
bool primary_selection_source_is_xwayland(
|
||||||
struct wlr_primary_selection_source *wlr_source);
|
const struct wlr_primary_selection_source *wlr_source);
|
||||||
|
|
||||||
void xwm_seat_handle_start_drag(struct wlr_xwm *xwm, struct wlr_drag *drag);
|
void xwm_seat_handle_start_drag(struct wlr_xwm *xwm, struct wlr_drag *drag);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
project(
|
project(
|
||||||
'wlroots',
|
'wlroots',
|
||||||
'c',
|
'c',
|
||||||
version: '0.20.0-rc4',
|
version: '0.21.0-dev',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
meson_version: '>=1.3',
|
meson_version: '>=1.3',
|
||||||
default_options: [
|
default_options: [
|
||||||
|
|
@ -178,6 +178,10 @@ if get_option('examples')
|
||||||
subdir('tinywl')
|
subdir('tinywl')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if get_option('tests')
|
||||||
|
subdir('test')
|
||||||
|
endif
|
||||||
|
|
||||||
pkgconfig = import('pkgconfig')
|
pkgconfig = import('pkgconfig')
|
||||||
pkgconfig.generate(
|
pkgconfig.generate(
|
||||||
lib_wlr,
|
lib_wlr,
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,6 @@ option('backends', type: 'array', choices: ['auto', 'drm', 'libinput', 'x11'], v
|
||||||
option('allocators', type: 'array', choices: ['auto', 'gbm', 'udmabuf'], value: ['auto'],
|
option('allocators', type: 'array', choices: ['auto', 'gbm', 'udmabuf'], value: ['auto'],
|
||||||
description: 'Select built-in allocators')
|
description: 'Select built-in allocators')
|
||||||
option('session', type: 'feature', value: 'auto', description: 'Enable session support')
|
option('session', type: 'feature', value: 'auto', description: 'Enable session support')
|
||||||
|
option('tests', type: 'boolean', value: true, description: 'Build tests and benchmarks')
|
||||||
option('color-management', type: 'feature', value: 'auto', description: 'Enable support for color management')
|
option('color-management', type: 'feature', value: 'auto', description: 'Enable support for color management')
|
||||||
option('libliftoff', type: 'feature', value: 'auto', description: 'Enable support for libliftoff')
|
option('libliftoff', type: 'feature', value: 'auto', description: 'Enable support for libliftoff')
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
@ -214,14 +222,8 @@ bool wlr_drm_syncobj_timeline_waiter_init(struct wlr_drm_syncobj_timeline_waiter
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct drm_syncobj_eventfd syncobj_eventfd = {
|
if (drmSyncobjEventfd(timeline->drm_fd, timeline->handle, point, ev_fd, flags) != 0) {
|
||||||
.handle = timeline->handle,
|
wlr_log_errno(WLR_ERROR, "drmSyncobjEventfd() failed");
|
||||||
.flags = flags,
|
|
||||||
.point = point,
|
|
||||||
.fd = ev_fd,
|
|
||||||
};
|
|
||||||
if (drmIoctl(timeline->drm_fd, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobj_eventfd) != 0) {
|
|
||||||
wlr_log_errno(WLR_ERROR, "DRM_IOCTL_SYNCOBJ_EVENTFD failed");
|
|
||||||
close(ev_fd);
|
close(ev_fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
static const struct wlr_renderer_impl renderer_impl;
|
static const struct wlr_renderer_impl renderer_impl;
|
||||||
static const struct wlr_render_timer_impl render_timer_impl;
|
static const struct wlr_render_timer_impl render_timer_impl;
|
||||||
|
|
||||||
bool wlr_renderer_is_gles2(struct wlr_renderer *wlr_renderer) {
|
bool wlr_renderer_is_gles2(const struct wlr_renderer *wlr_renderer) {
|
||||||
return wlr_renderer->impl == &renderer_impl;
|
return wlr_renderer->impl == &renderer_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,7 +40,7 @@ struct wlr_gles2_renderer *gles2_get_renderer(
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wlr_render_timer_is_gles2(struct wlr_render_timer *timer) {
|
bool wlr_render_timer_is_gles2(const struct wlr_render_timer *timer) {
|
||||||
return timer->impl == &render_timer_impl;
|
return timer->impl == &render_timer_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
#include <GLES2/gl2ext.h>
|
#include <GLES2/gl2ext.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <wayland-server-protocol.h>
|
#include <wayland-server-protocol.h>
|
||||||
#include <wayland-util.h>
|
#include <wayland-util.h>
|
||||||
|
#include <wlr/render/drm_syncobj.h>
|
||||||
#include <wlr/render/egl.h>
|
#include <wlr/render/egl.h>
|
||||||
#include <wlr/render/interface.h>
|
#include <wlr/render/interface.h>
|
||||||
#include <wlr/render/wlr_texture.h>
|
#include <wlr/render/wlr_texture.h>
|
||||||
|
|
@ -16,7 +18,7 @@
|
||||||
|
|
||||||
static const struct wlr_texture_impl texture_impl;
|
static const struct wlr_texture_impl texture_impl;
|
||||||
|
|
||||||
bool wlr_texture_is_gles2(struct wlr_texture *wlr_texture) {
|
bool wlr_texture_is_gles2(const struct wlr_texture *wlr_texture) {
|
||||||
return wlr_texture->impl == &texture_impl;
|
return wlr_texture->impl == &texture_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,6 +203,27 @@ static bool gles2_texture_read_pixels(struct wlr_texture *wlr_texture,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options->wait_timeline != NULL) {
|
||||||
|
int sync_file_fd =
|
||||||
|
wlr_drm_syncobj_timeline_export_sync_file(options->wait_timeline, options->wait_point);
|
||||||
|
if (sync_file_fd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_gles2_renderer *renderer = texture->renderer;
|
||||||
|
EGLSyncKHR sync = wlr_egl_create_sync(renderer->egl, sync_file_fd);
|
||||||
|
close(sync_file_fd);
|
||||||
|
if (sync == EGL_NO_SYNC_KHR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = wlr_egl_wait_sync(renderer->egl, sync);
|
||||||
|
wlr_egl_destroy_sync(renderer->egl, sync);
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure any pending drawing is finished before we try to read it
|
// Make sure any pending drawing is finished before we try to read it
|
||||||
glFinish();
|
glFinish();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
static const struct wlr_renderer_impl renderer_impl;
|
static const struct wlr_renderer_impl renderer_impl;
|
||||||
|
|
||||||
bool wlr_renderer_is_pixman(struct wlr_renderer *wlr_renderer) {
|
bool wlr_renderer_is_pixman(const struct wlr_renderer *wlr_renderer) {
|
||||||
return wlr_renderer->impl == &renderer_impl;
|
return wlr_renderer->impl == &renderer_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,7 +69,7 @@ static struct wlr_pixman_buffer *get_buffer(
|
||||||
|
|
||||||
static const struct wlr_texture_impl texture_impl;
|
static const struct wlr_texture_impl texture_impl;
|
||||||
|
|
||||||
bool wlr_texture_is_pixman(struct wlr_texture *texture) {
|
bool wlr_texture_is_pixman(const struct wlr_texture *texture) {
|
||||||
return texture->impl == &texture_impl;
|
return texture->impl == &texture_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,53 +99,6 @@ static void render_pass_destroy(struct wlr_vk_render_pass *pass) {
|
||||||
free(pass);
|
free(pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VkSemaphore render_pass_wait_sync_file(struct wlr_vk_render_pass *pass,
|
|
||||||
size_t sem_index, int sync_file_fd) {
|
|
||||||
struct wlr_vk_renderer *renderer = pass->renderer;
|
|
||||||
struct wlr_vk_command_buffer *render_cb = pass->command_buffer;
|
|
||||||
VkResult res;
|
|
||||||
|
|
||||||
VkSemaphore *wait_semaphores = render_cb->wait_semaphores.data;
|
|
||||||
size_t wait_semaphores_len = render_cb->wait_semaphores.size / sizeof(wait_semaphores[0]);
|
|
||||||
|
|
||||||
VkSemaphore *sem_ptr;
|
|
||||||
if (sem_index >= wait_semaphores_len) {
|
|
||||||
sem_ptr = wl_array_add(&render_cb->wait_semaphores, sizeof(*sem_ptr));
|
|
||||||
if (sem_ptr == NULL) {
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
*sem_ptr = VK_NULL_HANDLE;
|
|
||||||
} else {
|
|
||||||
sem_ptr = &wait_semaphores[sem_index];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*sem_ptr == VK_NULL_HANDLE) {
|
|
||||||
VkSemaphoreCreateInfo semaphore_info = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
|
||||||
};
|
|
||||||
res = vkCreateSemaphore(renderer->dev->dev, &semaphore_info, NULL, sem_ptr);
|
|
||||||
if (res != VK_SUCCESS) {
|
|
||||||
wlr_vk_error("vkCreateSemaphore", res);
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImportSemaphoreFdInfoKHR import_info = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
|
|
||||||
.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
|
|
||||||
.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
|
|
||||||
.semaphore = *sem_ptr,
|
|
||||||
.fd = sync_file_fd,
|
|
||||||
};
|
|
||||||
res = renderer->dev->api.vkImportSemaphoreFdKHR(renderer->dev->dev, &import_info);
|
|
||||||
if (res != VK_SUCCESS) {
|
|
||||||
wlr_vk_error("vkImportSemaphoreFdKHR", res);
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *sem_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool render_pass_wait_render_buffer(struct wlr_vk_render_pass *pass,
|
static bool render_pass_wait_render_buffer(struct wlr_vk_render_pass *pass,
|
||||||
VkSemaphoreSubmitInfoKHR *render_wait, uint32_t *render_wait_len_ptr) {
|
VkSemaphoreSubmitInfoKHR *render_wait, uint32_t *render_wait_len_ptr) {
|
||||||
int sync_file_fds[WLR_DMABUF_MAX_PLANES];
|
int sync_file_fds[WLR_DMABUF_MAX_PLANES];
|
||||||
|
|
@ -162,7 +115,8 @@ static bool render_pass_wait_render_buffer(struct wlr_vk_render_pass *pass,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSemaphore sem = render_pass_wait_sync_file(pass, *render_wait_len_ptr, sync_file_fds[i]);
|
VkSemaphore sem = vulkan_command_buffer_wait_sync_file(pass->renderer,
|
||||||
|
pass->command_buffer, *render_wait_len_ptr, sync_file_fds[i]);
|
||||||
if (sem == VK_NULL_HANDLE) {
|
if (sem == VK_NULL_HANDLE) {
|
||||||
close(sync_file_fds[i]);
|
close(sync_file_fds[i]);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -431,7 +385,8 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSemaphore sem = render_pass_wait_sync_file(pass, render_wait_len, sync_file_fds[i]);
|
VkSemaphore sem = vulkan_command_buffer_wait_sync_file(renderer, render_cb,
|
||||||
|
render_wait_len, sync_file_fds[i]);
|
||||||
if (sem == VK_NULL_HANDLE) {
|
if (sem == VK_NULL_HANDLE) {
|
||||||
close(sync_file_fds[i]);
|
close(sync_file_fds[i]);
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ static bool default_debug = true;
|
||||||
|
|
||||||
static const struct wlr_renderer_impl renderer_impl;
|
static const struct wlr_renderer_impl renderer_impl;
|
||||||
|
|
||||||
bool wlr_renderer_is_vk(struct wlr_renderer *wlr_renderer) {
|
bool wlr_renderer_is_vk(const struct wlr_renderer *wlr_renderer) {
|
||||||
return wlr_renderer->impl == &renderer_impl;
|
return wlr_renderer->impl == &renderer_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -379,7 +379,52 @@ VkCommandBuffer vulkan_record_stage_cb(struct wlr_vk_renderer *renderer) {
|
||||||
return renderer->stage.cb->vk;
|
return renderer->stage.cb->vk;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer) {
|
VkSemaphore vulkan_command_buffer_wait_sync_file(struct wlr_vk_renderer *renderer,
|
||||||
|
struct wlr_vk_command_buffer *render_cb, size_t sem_index, int sync_file_fd) {
|
||||||
|
VkResult res;
|
||||||
|
|
||||||
|
VkSemaphore *wait_semaphores = render_cb->wait_semaphores.data;
|
||||||
|
size_t wait_semaphores_len = render_cb->wait_semaphores.size / sizeof(wait_semaphores[0]);
|
||||||
|
|
||||||
|
VkSemaphore *sem_ptr;
|
||||||
|
if (sem_index >= wait_semaphores_len) {
|
||||||
|
sem_ptr = wl_array_add(&render_cb->wait_semaphores, sizeof(*sem_ptr));
|
||||||
|
if (sem_ptr == NULL) {
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
*sem_ptr = VK_NULL_HANDLE;
|
||||||
|
} else {
|
||||||
|
sem_ptr = &wait_semaphores[sem_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*sem_ptr == VK_NULL_HANDLE) {
|
||||||
|
VkSemaphoreCreateInfo semaphore_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||||
|
};
|
||||||
|
res = vkCreateSemaphore(renderer->dev->dev, &semaphore_info, NULL, sem_ptr);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("vkCreateSemaphore", res);
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImportSemaphoreFdInfoKHR import_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
|
||||||
|
.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
|
||||||
|
.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
|
||||||
|
.semaphore = *sem_ptr,
|
||||||
|
.fd = sync_file_fd,
|
||||||
|
};
|
||||||
|
res = renderer->dev->api.vkImportSemaphoreFdKHR(renderer->dev->dev, &import_info);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("vkImportSemaphoreFdKHR", res);
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *sem_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer, int wait_sync_file_fd) {
|
||||||
if (renderer->stage.cb == NULL) {
|
if (renderer->stage.cb == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -389,9 +434,12 @@ bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer) {
|
||||||
|
|
||||||
uint64_t timeline_point = vulkan_end_command_buffer(cb, renderer);
|
uint64_t timeline_point = vulkan_end_command_buffer(cb, renderer);
|
||||||
if (timeline_point == 0) {
|
if (timeline_point == 0) {
|
||||||
|
close(wait_sync_file_fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkSemaphore wait_semaphore;
|
||||||
|
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
|
||||||
VkTimelineSemaphoreSubmitInfoKHR timeline_submit_info = {
|
VkTimelineSemaphoreSubmitInfoKHR timeline_submit_info = {
|
||||||
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR,
|
||||||
.signalSemaphoreValueCount = 1,
|
.signalSemaphoreValueCount = 1,
|
||||||
|
|
@ -405,6 +453,18 @@ bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer) {
|
||||||
.signalSemaphoreCount = 1,
|
.signalSemaphoreCount = 1,
|
||||||
.pSignalSemaphores = &renderer->timeline_semaphore,
|
.pSignalSemaphores = &renderer->timeline_semaphore,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (wait_sync_file_fd != -1) {
|
||||||
|
wait_semaphore = vulkan_command_buffer_wait_sync_file(renderer, cb, 0, wait_sync_file_fd);
|
||||||
|
if (wait_semaphore == VK_NULL_HANDLE) {
|
||||||
|
close(wait_sync_file_fd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
submit_info.waitSemaphoreCount = 1;
|
||||||
|
submit_info.pWaitSemaphores = &wait_semaphore;
|
||||||
|
submit_info.pWaitDstStageMask = &wait_stage;
|
||||||
|
}
|
||||||
|
|
||||||
VkResult res = vkQueueSubmit(renderer->dev->queue, 1, &submit_info, VK_NULL_HANDLE);
|
VkResult res = vkQueueSubmit(renderer->dev->queue, 1, &submit_info, VK_NULL_HANDLE);
|
||||||
if (res != VK_SUCCESS) {
|
if (res != VK_SUCCESS) {
|
||||||
wlr_vk_error("vkQueueSubmit", res);
|
wlr_vk_error("vkQueueSubmit", res);
|
||||||
|
|
@ -1188,7 +1248,7 @@ static void vulkan_destroy(struct wlr_renderer *wlr_renderer) {
|
||||||
vkDestroyPipelineLayout(dev->dev, pipeline_layout->vk, NULL);
|
vkDestroyPipelineLayout(dev->dev, pipeline_layout->vk, NULL);
|
||||||
vkDestroyDescriptorSetLayout(dev->dev, pipeline_layout->ds, NULL);
|
vkDestroyDescriptorSetLayout(dev->dev, pipeline_layout->ds, NULL);
|
||||||
vkDestroySampler(dev->dev, pipeline_layout->sampler, NULL);
|
vkDestroySampler(dev->dev, pipeline_layout->sampler, NULL);
|
||||||
vkDestroySamplerYcbcrConversion(dev->dev, pipeline_layout->ycbcr.conversion, NULL);
|
renderer->dev->api.vkDestroySamplerYcbcrConversionKHR(dev->dev, pipeline_layout->ycbcr.conversion, NULL);
|
||||||
free(pipeline_layout);
|
free(pipeline_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1218,7 +1278,8 @@ bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,
|
||||||
VkFormat src_format, VkImage src_image,
|
VkFormat src_format, VkImage src_image,
|
||||||
uint32_t drm_format, uint32_t stride,
|
uint32_t drm_format, uint32_t stride,
|
||||||
uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y,
|
uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y,
|
||||||
uint32_t dst_x, uint32_t dst_y, void *data) {
|
uint32_t dst_x, uint32_t dst_y, void *data,
|
||||||
|
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point) {
|
||||||
VkDevice dev = vk_renderer->dev->dev;
|
VkDevice dev = vk_renderer->dev->dev;
|
||||||
|
|
||||||
const struct wlr_pixel_format_info *pixel_format_info = drm_get_pixel_format_info(drm_format);
|
const struct wlr_pixel_format_info *pixel_format_info = drm_get_pixel_format_info(drm_format);
|
||||||
|
|
@ -1404,7 +1465,17 @@ bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
VK_ACCESS_MEMORY_READ_BIT);
|
VK_ACCESS_MEMORY_READ_BIT);
|
||||||
|
|
||||||
if (!vulkan_submit_stage_wait(vk_renderer)) {
|
int wait_sync_file_fd = -1;
|
||||||
|
if (wait_timeline != NULL) {
|
||||||
|
wait_sync_file_fd = wlr_drm_syncobj_timeline_export_sync_file(wait_timeline, wait_point);
|
||||||
|
if (wait_sync_file_fd < 0) {
|
||||||
|
wlr_log(WLR_ERROR, "Failed to export wait timeline point as sync_file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vulkan_submit_stage_wait(vk_renderer, wait_sync_file_fd)) {
|
||||||
|
close(wait_sync_file_fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2049,10 +2120,10 @@ struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout(
|
||||||
.yChromaOffset = VK_CHROMA_LOCATION_MIDPOINT,
|
.yChromaOffset = VK_CHROMA_LOCATION_MIDPOINT,
|
||||||
.chromaFilter = VK_FILTER_LINEAR,
|
.chromaFilter = VK_FILTER_LINEAR,
|
||||||
};
|
};
|
||||||
res = vkCreateSamplerYcbcrConversion(renderer->dev->dev,
|
res = renderer->dev->api.vkCreateSamplerYcbcrConversionKHR(renderer->dev->dev,
|
||||||
&conversion_create_info, NULL, &pipeline_layout->ycbcr.conversion);
|
&conversion_create_info, NULL, &pipeline_layout->ycbcr.conversion);
|
||||||
if (res != VK_SUCCESS) {
|
if (res != VK_SUCCESS) {
|
||||||
wlr_vk_error("vkCreateSamplerYcbcrConversion", res);
|
wlr_vk_error("vkCreateSamplerYcbcrConversionKHR", res);
|
||||||
free(pipeline_layout);
|
free(pipeline_layout);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
static const struct wlr_texture_impl texture_impl;
|
static const struct wlr_texture_impl texture_impl;
|
||||||
|
|
||||||
bool wlr_texture_is_vk(struct wlr_texture *wlr_texture) {
|
bool wlr_texture_is_vk(const struct wlr_texture *wlr_texture) {
|
||||||
return wlr_texture->impl == &texture_impl;
|
return wlr_texture->impl == &texture_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,7 +238,8 @@ static bool vulkan_texture_read_pixels(struct wlr_texture *wlr_texture,
|
||||||
void *p = wlr_texture_read_pixel_options_get_data(options);
|
void *p = wlr_texture_read_pixel_options_get_data(options);
|
||||||
|
|
||||||
return vulkan_read_pixels(texture->renderer, texture->format->vk, texture->image,
|
return vulkan_read_pixels(texture->renderer, texture->format->vk, texture->image,
|
||||||
options->format, options->stride, src.width, src.height, src.x, src.y, 0, 0, p);
|
options->format, options->stride, src.width, src.height, src.x, src.y, 0, 0, p,
|
||||||
|
options->wait_timeline, options->wait_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t vulkan_texture_preferred_read_format(struct wlr_texture *wlr_texture) {
|
static uint32_t vulkan_texture_preferred_read_format(struct wlr_texture *wlr_texture) {
|
||||||
|
|
@ -653,7 +654,7 @@ VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer,
|
||||||
.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
|
.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
|
||||||
};
|
};
|
||||||
|
|
||||||
vkGetImageMemoryRequirements2(dev, &memri, &memr);
|
renderer->dev->api.vkGetImageMemoryRequirements2KHR(dev, &memri, &memr);
|
||||||
int mem = vulkan_find_mem_type(renderer->dev, 0,
|
int mem = vulkan_find_mem_type(renderer->dev, 0,
|
||||||
memr.memoryRequirements.memoryTypeBits & fdp.memoryTypeBits);
|
memr.memoryRequirements.memoryTypeBits & fdp.memoryTypeBits);
|
||||||
if (mem < 0) {
|
if (mem < 0) {
|
||||||
|
|
@ -712,7 +713,7 @@ VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res = vkBindImageMemory2(dev, mem_count, bindi);
|
res = renderer->dev->api.vkBindImageMemory2KHR(dev, mem_count, bindi);
|
||||||
if (res != VK_SUCCESS) {
|
if (res != VK_SUCCESS) {
|
||||||
wlr_vk_error("vkBindMemory failed", res);
|
wlr_vk_error("vkBindMemory failed", res);
|
||||||
goto error_image;
|
goto error_image;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -81,21 +81,6 @@ static VKAPI_ATTR VkBool32 debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_vk_instance *vulkan_instance_create(bool debug) {
|
struct wlr_vk_instance *vulkan_instance_create(bool debug) {
|
||||||
// we require vulkan 1.1
|
|
||||||
PFN_vkEnumerateInstanceVersion pfEnumInstanceVersion =
|
|
||||||
(PFN_vkEnumerateInstanceVersion)
|
|
||||||
vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceVersion");
|
|
||||||
if (!pfEnumInstanceVersion) {
|
|
||||||
wlr_log(WLR_ERROR, "wlroots requires vulkan 1.1 which is not available");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ini_version;
|
|
||||||
if (pfEnumInstanceVersion(&ini_version) != VK_SUCCESS ||
|
|
||||||
ini_version < VK_API_VERSION_1_1) {
|
|
||||||
wlr_log(WLR_ERROR, "wlroots requires vulkan 1.1 which is not available");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t avail_extc = 0;
|
uint32_t avail_extc = 0;
|
||||||
VkResult res;
|
VkResult res;
|
||||||
|
|
@ -125,7 +110,18 @@ struct wlr_vk_instance *vulkan_instance_create(bool debug) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t extensions_len = 0;
|
size_t extensions_len = 0;
|
||||||
const char *extensions[1] = {0};
|
const char *extensions[8] = {0};
|
||||||
|
extensions[extensions_len++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME;
|
||||||
|
extensions[extensions_len++] = VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME;
|
||||||
|
extensions[extensions_len++] = VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < extensions_len; i++) {
|
||||||
|
if (!check_extension(avail_ext_props, avail_extc, extensions[i])) {
|
||||||
|
wlr_log(WLR_ERROR, "vulkan: required instance extension %s not found",
|
||||||
|
extensions[i]);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool debug_utils_found = false;
|
bool debug_utils_found = false;
|
||||||
if (debug && check_extension(avail_ext_props, avail_extc,
|
if (debug && check_extension(avail_ext_props, avail_extc,
|
||||||
|
|
@ -140,7 +136,7 @@ struct wlr_vk_instance *vulkan_instance_create(bool debug) {
|
||||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||||
.pEngineName = "wlroots",
|
.pEngineName = "wlroots",
|
||||||
.engineVersion = WLR_VERSION_NUM,
|
.engineVersion = WLR_VERSION_NUM,
|
||||||
.apiVersion = VK_API_VERSION_1_1,
|
.apiVersion = VK_API_VERSION_1_0,
|
||||||
};
|
};
|
||||||
|
|
||||||
VkInstanceCreateInfo instance_info = {
|
VkInstanceCreateInfo instance_info = {
|
||||||
|
|
@ -282,20 +278,10 @@ VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd)
|
||||||
for (uint32_t i = 0; i < num_phdevs; ++i) {
|
for (uint32_t i = 0; i < num_phdevs; ++i) {
|
||||||
VkPhysicalDevice phdev = phdevs[i];
|
VkPhysicalDevice phdev = phdevs[i];
|
||||||
|
|
||||||
// check whether device supports vulkan 1.1, needed for
|
|
||||||
// vkGetPhysicalDeviceProperties2
|
|
||||||
VkPhysicalDeviceProperties phdev_props;
|
VkPhysicalDeviceProperties phdev_props;
|
||||||
vkGetPhysicalDeviceProperties(phdev, &phdev_props);
|
vkGetPhysicalDeviceProperties(phdev, &phdev_props);
|
||||||
|
|
||||||
log_phdev(&phdev_props);
|
log_phdev(&phdev_props);
|
||||||
|
|
||||||
if (phdev_props.apiVersion < VK_API_VERSION_1_1) {
|
|
||||||
// NOTE: we could additionally check whether the
|
|
||||||
// VkPhysicalDeviceProperties2KHR extension is supported but
|
|
||||||
// implementations not supporting 1.1 are unlikely in future
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for extensions
|
// check for extensions
|
||||||
uint32_t avail_extc = 0;
|
uint32_t avail_extc = 0;
|
||||||
res = vkEnumerateDeviceExtensionProperties(phdev, NULL,
|
res = vkEnumerateDeviceExtensionProperties(phdev, NULL,
|
||||||
|
|
@ -474,6 +460,12 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
|
||||||
extensions[extensions_len++] = VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME;
|
extensions[extensions_len++] = VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME;
|
||||||
extensions[extensions_len++] = VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME; // or vulkan 1.2
|
extensions[extensions_len++] = VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME; // or vulkan 1.2
|
||||||
extensions[extensions_len++] = VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME; // or vulkan 1.3
|
extensions[extensions_len++] = VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME; // or vulkan 1.3
|
||||||
|
extensions[extensions_len++] = VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME; // or vulkan 1.1
|
||||||
|
extensions[extensions_len++] = VK_KHR_BIND_MEMORY_2_EXTENSION_NAME; // or vulkan 1.1
|
||||||
|
extensions[extensions_len++] = VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME; // or vulkan 1.1
|
||||||
|
extensions[extensions_len++] = VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME; // or vulkan 1.1
|
||||||
|
extensions[extensions_len++] = VK_KHR_MAINTENANCE_1_EXTENSION_NAME; // or vulkan 1.1
|
||||||
|
extensions[extensions_len++] = VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME; // or vulkan 1.1
|
||||||
|
|
||||||
for (size_t i = 0; i < extensions_len; i++) {
|
for (size_t i = 0; i < extensions_len; i++) {
|
||||||
if (!check_extension(avail_ext_props, avail_extc, extensions[i])) {
|
if (!check_extension(avail_ext_props, avail_extc, extensions[i])) {
|
||||||
|
|
@ -564,17 +556,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, "
|
||||||
|
|
@ -630,6 +622,10 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
|
||||||
load_device_proc(dev, "vkGetSemaphoreCounterValueKHR",
|
load_device_proc(dev, "vkGetSemaphoreCounterValueKHR",
|
||||||
&dev->api.vkGetSemaphoreCounterValueKHR);
|
&dev->api.vkGetSemaphoreCounterValueKHR);
|
||||||
load_device_proc(dev, "vkQueueSubmit2KHR", &dev->api.vkQueueSubmit2KHR);
|
load_device_proc(dev, "vkQueueSubmit2KHR", &dev->api.vkQueueSubmit2KHR);
|
||||||
|
load_device_proc(dev, "vkBindImageMemory2KHR", &dev->api.vkBindImageMemory2KHR);
|
||||||
|
load_device_proc(dev, "vkCreateSamplerYcbcrConversionKHR", &dev->api.vkCreateSamplerYcbcrConversionKHR);
|
||||||
|
load_device_proc(dev, "vkDestroySamplerYcbcrConversionKHR", &dev->api.vkDestroySamplerYcbcrConversionKHR);
|
||||||
|
load_device_proc(dev, "vkGetImageMemoryRequirements2KHR", &dev->api.vkGetImageMemoryRequirements2KHR);
|
||||||
|
|
||||||
if (has_external_semaphore_fd) {
|
if (has_external_semaphore_fd) {
|
||||||
load_device_proc(dev, "vkGetSemaphoreFdKHR", &dev->api.vkGetSemaphoreFdKHR);
|
load_device_proc(dev, "vkGetSemaphoreFdKHR", &dev->api.vkGetSemaphoreFdKHR);
|
||||||
|
|
|
||||||
154
test/bench_scene.c
Normal file
154
test/bench_scene.c
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <wlr/types/wlr_scene.h>
|
||||||
|
|
||||||
|
struct tree_spec {
|
||||||
|
// Parameters for the tree we'll construct
|
||||||
|
int depth;
|
||||||
|
int branching;
|
||||||
|
int rect_size;
|
||||||
|
int spread;
|
||||||
|
|
||||||
|
// Stats around the tree we built
|
||||||
|
int tree_count;
|
||||||
|
int rect_count;
|
||||||
|
int max_x;
|
||||||
|
int max_y;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int max(int a, int b) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double timespec_diff_msec(struct timespec *start, struct timespec *end) {
|
||||||
|
return (double)(end->tv_sec - start->tv_sec) * 1e3 +
|
||||||
|
(double)(end->tv_nsec - start->tv_nsec) / 1e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool build_tree(struct wlr_scene_tree *parent, struct tree_spec *spec,
|
||||||
|
int depth, int x, int y) {
|
||||||
|
|
||||||
|
if (depth == spec->depth) {
|
||||||
|
float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
|
struct wlr_scene_rect *rect =
|
||||||
|
wlr_scene_rect_create(parent, spec->rect_size, spec->rect_size, color);
|
||||||
|
if (rect == NULL) {
|
||||||
|
fprintf(stderr, "wlr_scene_rect_create failed\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
wlr_scene_node_set_position(&rect->node, x, y);
|
||||||
|
spec->max_x = max(spec->max_x, x + spec->rect_size);
|
||||||
|
spec->max_y = max(spec->max_y, y + spec->rect_size);
|
||||||
|
spec->rect_count++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < spec->branching; i++) {
|
||||||
|
struct wlr_scene_tree *child = wlr_scene_tree_create(parent);
|
||||||
|
if (child == NULL) {
|
||||||
|
fprintf(stderr, "wlr_scene_tree_create failed\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
spec->tree_count++;
|
||||||
|
int offset = i * spec->spread;
|
||||||
|
wlr_scene_node_set_position(&child->node, offset, offset);
|
||||||
|
if (!build_tree(child, spec, depth + 1, x + offset, y + offset)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bench_create_tree(struct wlr_scene *scene, struct tree_spec *spec) {
|
||||||
|
struct timespec start, end;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||||
|
if (!build_tree(&scene->tree, spec, 0, 0, 0)) {
|
||||||
|
fprintf(stderr, "build_tree failed\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||||
|
|
||||||
|
printf("Built tree with %d tree nodes, %d rect nodes\n\n",
|
||||||
|
spec->tree_count, spec->rect_count);
|
||||||
|
|
||||||
|
double elapsed = timespec_diff_msec(&start, &end);
|
||||||
|
int nodes = spec->tree_count + spec->rect_count;
|
||||||
|
printf("create test tree: %d nodes, %.3f ms, %.0f nodes/ms\n",
|
||||||
|
nodes, elapsed, nodes / elapsed);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bench_scene_node_at(struct wlr_scene *scene, struct tree_spec *spec) {
|
||||||
|
struct timespec start, end;
|
||||||
|
int iters = 10000;
|
||||||
|
int hits = 0;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||||
|
for (int i = 0; i < iters; i++) {
|
||||||
|
// Spread lookups across the tree extent
|
||||||
|
double lx = (double)(i * 97 % spec->max_x);
|
||||||
|
double ly = (double)(i * 53 % spec->max_y);
|
||||||
|
double nx, ny;
|
||||||
|
struct wlr_scene_node *node =
|
||||||
|
wlr_scene_node_at(&scene->tree.node, lx, ly, &nx, &ny);
|
||||||
|
if (node != NULL) {
|
||||||
|
hits++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||||
|
|
||||||
|
double elapsed = timespec_diff_msec(&start, &end);
|
||||||
|
int nodes = (spec->tree_count + spec->rect_count) * iters;
|
||||||
|
printf("wlr_scene_node_at: %d iters, %.3f ms, %.0f nodes/ms (hits: %d/%d)\n",
|
||||||
|
iters, elapsed, nodes / elapsed, hits, iters);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void noop_iterator(struct wlr_scene_buffer *buffer,
|
||||||
|
int sx, int sy, void *user_data) {
|
||||||
|
(void)buffer;
|
||||||
|
(void)sx;
|
||||||
|
(void)sy;
|
||||||
|
int *cnt = user_data;
|
||||||
|
(*cnt)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bench_scene_node_for_each_buffer(struct wlr_scene *scene, struct tree_spec *spec) {
|
||||||
|
struct timespec start, end;
|
||||||
|
int iters = 10000;
|
||||||
|
int hits = 0;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||||
|
for (int i = 0; i < iters; i++) {
|
||||||
|
wlr_scene_node_for_each_buffer(&scene->tree.node,
|
||||||
|
noop_iterator, &hits);
|
||||||
|
}
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||||
|
|
||||||
|
double elapsed = timespec_diff_msec(&start, &end);
|
||||||
|
int nodes = (spec->tree_count + spec->rect_count) * iters;
|
||||||
|
printf("wlr_scene_node_for_each_buffer: %d iters, %.3f ms, %.0f nodes/ms (hits: %d/%d)\n",
|
||||||
|
iters, elapsed, nodes / elapsed, hits, iters);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct wlr_scene *scene = wlr_scene_create();
|
||||||
|
if (scene == NULL) {
|
||||||
|
fprintf(stderr, "wlr_scene_create failed\n");
|
||||||
|
return 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tree_spec spec = {
|
||||||
|
.depth = 5,
|
||||||
|
.branching = 5,
|
||||||
|
.rect_size = 10,
|
||||||
|
.spread = 100,
|
||||||
|
};
|
||||||
|
if (!bench_create_tree(scene, &spec)) {
|
||||||
|
return 99;
|
||||||
|
}
|
||||||
|
bench_scene_node_at(scene, &spec);
|
||||||
|
bench_scene_node_for_each_buffer(scene, &spec);
|
||||||
|
|
||||||
|
wlr_scene_node_destroy(&scene->tree.node);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
10
test/meson.build
Normal file
10
test/meson.build
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
test(
|
||||||
|
'box',
|
||||||
|
executable('test-box', 'test_box.c', dependencies: wlroots),
|
||||||
|
)
|
||||||
|
|
||||||
|
benchmark(
|
||||||
|
'scene',
|
||||||
|
executable('bench-scene', 'bench_scene.c', dependencies: wlroots),
|
||||||
|
timeout: 30,
|
||||||
|
)
|
||||||
149
test/test_box.c
Normal file
149
test/test_box.c
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <wlr/util/box.h>
|
||||||
|
|
||||||
|
static void test_box_empty(void) {
|
||||||
|
// NULL is empty
|
||||||
|
assert(wlr_box_empty(NULL));
|
||||||
|
|
||||||
|
// Zero width/height
|
||||||
|
struct wlr_box box = { .x = 0, .y = 0, .width = 0, .height = 10 };
|
||||||
|
assert(wlr_box_empty(&box));
|
||||||
|
box = (struct wlr_box){ .x = 0, .y = 0, .width = 10, .height = 0 };
|
||||||
|
assert(wlr_box_empty(&box));
|
||||||
|
|
||||||
|
// Negative width/height
|
||||||
|
box = (struct wlr_box){ .x = 0, .y = 0, .width = -1, .height = 10 };
|
||||||
|
assert(wlr_box_empty(&box));
|
||||||
|
box = (struct wlr_box){ .x = 0, .y = 0, .width = 10, .height = -1 };
|
||||||
|
assert(wlr_box_empty(&box));
|
||||||
|
|
||||||
|
// Valid box
|
||||||
|
box = (struct wlr_box){ .x = 0, .y = 0, .width = 10, .height = 10 };
|
||||||
|
assert(!wlr_box_empty(&box));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_box_intersection(void) {
|
||||||
|
struct wlr_box dest;
|
||||||
|
|
||||||
|
// Overlapping
|
||||||
|
struct wlr_box a = { .x = 0, .y = 0, .width = 100, .height = 100 };
|
||||||
|
struct wlr_box b = { .x = 50, .y = 50, .width = 100, .height = 100 };
|
||||||
|
assert(wlr_box_intersection(&dest, &a, &b));
|
||||||
|
assert(dest.x == 50 && dest.y == 50 &&
|
||||||
|
dest.width == 50 && dest.height == 50);
|
||||||
|
|
||||||
|
// Non-overlapping
|
||||||
|
b = (struct wlr_box){ .x = 200, .y = 200, .width = 50, .height = 50 };
|
||||||
|
assert(!wlr_box_intersection(&dest, &a, &b));
|
||||||
|
assert(dest.width == 0 && dest.height == 0);
|
||||||
|
|
||||||
|
// Touching edges
|
||||||
|
b = (struct wlr_box){ .x = 100, .y = 0, .width = 50, .height = 50 };
|
||||||
|
assert(!wlr_box_intersection(&dest, &a, &b));
|
||||||
|
|
||||||
|
// Self-intersection
|
||||||
|
assert(wlr_box_intersection(&dest, &a, &a));
|
||||||
|
assert(dest.x == a.x && dest.y == a.y &&
|
||||||
|
dest.width == a.width && dest.height == a.height);
|
||||||
|
|
||||||
|
// Empty input
|
||||||
|
struct wlr_box empty = { .x = 0, .y = 0, .width = 0, .height = 0 };
|
||||||
|
assert(!wlr_box_intersection(&dest, &a, &empty));
|
||||||
|
|
||||||
|
// NULL input
|
||||||
|
assert(!wlr_box_intersection(&dest, &a, NULL));
|
||||||
|
assert(!wlr_box_intersection(&dest, NULL, &a));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_box_intersects_box(void) {
|
||||||
|
// Overlapping
|
||||||
|
struct wlr_box a = { .x = 0, .y = 0, .width = 100, .height = 100 };
|
||||||
|
struct wlr_box b = { .x = 50, .y = 50, .width = 100, .height = 100 };
|
||||||
|
assert(wlr_box_intersects(&a, &b));
|
||||||
|
|
||||||
|
// Non-overlapping
|
||||||
|
b = (struct wlr_box){ .x = 200, .y = 200, .width = 50, .height = 50 };
|
||||||
|
assert(!wlr_box_intersects(&a, &b));
|
||||||
|
|
||||||
|
// Touching edges
|
||||||
|
b = (struct wlr_box){ .x = 100, .y = 0, .width = 50, .height = 50 };
|
||||||
|
assert(!wlr_box_intersects(&a, &b));
|
||||||
|
|
||||||
|
// Self-intersection
|
||||||
|
assert(wlr_box_intersects(&a, &a));
|
||||||
|
|
||||||
|
// Empty input
|
||||||
|
struct wlr_box empty = { .x = 0, .y = 0, .width = 0, .height = 0 };
|
||||||
|
assert(!wlr_box_intersects(&a, &empty));
|
||||||
|
|
||||||
|
// NULL input
|
||||||
|
assert(!wlr_box_intersects(&a, NULL));
|
||||||
|
assert(!wlr_box_intersects(NULL, &a));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_box_contains_point(void) {
|
||||||
|
struct wlr_box box = { .x = 10, .y = 20, .width = 100, .height = 50 };
|
||||||
|
|
||||||
|
// Interior point
|
||||||
|
assert(wlr_box_contains_point(&box, 50, 40));
|
||||||
|
|
||||||
|
// Inclusive lower bound
|
||||||
|
assert(wlr_box_contains_point(&box, 10, 20));
|
||||||
|
|
||||||
|
// Exclusive upper bound
|
||||||
|
assert(!wlr_box_contains_point(&box, 110, 70));
|
||||||
|
assert(!wlr_box_contains_point(&box, 110, 40));
|
||||||
|
assert(!wlr_box_contains_point(&box, 50, 70));
|
||||||
|
|
||||||
|
// Outside
|
||||||
|
assert(!wlr_box_contains_point(&box, 5, 40));
|
||||||
|
assert(!wlr_box_contains_point(&box, 50, 15));
|
||||||
|
|
||||||
|
// Empty box
|
||||||
|
struct wlr_box empty = { .x = 0, .y = 0, .width = 0, .height = 0 };
|
||||||
|
assert(!wlr_box_contains_point(&empty, 0, 0));
|
||||||
|
|
||||||
|
// NULL
|
||||||
|
assert(!wlr_box_contains_point(NULL, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_box_contains_box(void) {
|
||||||
|
struct wlr_box outer = { .x = 0, .y = 0, .width = 100, .height = 100 };
|
||||||
|
|
||||||
|
// Fully contained
|
||||||
|
struct wlr_box inner = { .x = 10, .y = 10, .width = 50, .height = 50 };
|
||||||
|
assert(wlr_box_contains_box(&outer, &inner));
|
||||||
|
|
||||||
|
// Self-containment
|
||||||
|
assert(wlr_box_contains_box(&outer, &outer));
|
||||||
|
|
||||||
|
// Partial overlap — not contained
|
||||||
|
struct wlr_box partial = { .x = 50, .y = 50, .width = 100, .height = 100 };
|
||||||
|
assert(!wlr_box_contains_box(&outer, &partial));
|
||||||
|
|
||||||
|
// Empty inner
|
||||||
|
struct wlr_box empty = { .x = 0, .y = 0, .width = 0, .height = 0 };
|
||||||
|
assert(!wlr_box_contains_box(&outer, &empty));
|
||||||
|
|
||||||
|
// Empty outer
|
||||||
|
assert(!wlr_box_contains_box(&empty, &inner));
|
||||||
|
|
||||||
|
// NULL
|
||||||
|
assert(!wlr_box_contains_box(&outer, NULL));
|
||||||
|
assert(!wlr_box_contains_box(NULL, &outer));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
#ifdef NDEBUG
|
||||||
|
fprintf(stderr, "NDEBUG must be disabled for tests\n");
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
test_box_empty();
|
||||||
|
test_box_intersection();
|
||||||
|
test_box_intersects_box();
|
||||||
|
test_box_contains_point();
|
||||||
|
test_box_contains_box();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
PKG_CONFIG?=pkg-config
|
PKG_CONFIG?=pkg-config
|
||||||
|
|
||||||
PKGS="wlroots-0.20" wayland-server xkbcommon
|
PKGS="wlroots-0.21" wayland-server xkbcommon
|
||||||
CFLAGS_PKG_CONFIG!=$(PKG_CONFIG) --cflags $(PKGS)
|
CFLAGS_PKG_CONFIG!=$(PKG_CONFIG) --cflags $(PKGS)
|
||||||
CFLAGS+=$(CFLAGS_PKG_CONFIG)
|
CFLAGS+=$(CFLAGS_PKG_CONFIG)
|
||||||
LIBS!=$(PKG_CONFIG) --libs $(PKGS)
|
LIBS!=$(PKG_CONFIG) --libs $(PKGS)
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,13 +34,14 @@ struct scene_node_source_frame_event {
|
||||||
|
|
||||||
static size_t last_output_num = 0;
|
static size_t last_output_num = 0;
|
||||||
|
|
||||||
static void _get_scene_node_extents(struct wlr_scene_node *node, struct wlr_box *box, int lx, int ly) {
|
static void _get_scene_node_extents(struct wlr_scene_node *node, int lx, int ly,
|
||||||
|
int *x_min, int *y_min, int *x_max, int *y_max) {
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case WLR_SCENE_NODE_TREE:;
|
case WLR_SCENE_NODE_TREE:;
|
||||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||||
struct wlr_scene_node *child;
|
struct wlr_scene_node *child;
|
||||||
wl_list_for_each(child, &scene_tree->children, link) {
|
wl_list_for_each(child, &scene_tree->children, link) {
|
||||||
_get_scene_node_extents(child, box, lx + child->x, ly + child->y);
|
_get_scene_node_extents(child, lx + child->x, ly + child->y, x_min, y_min, x_max, y_max);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WLR_SCENE_NODE_RECT:
|
case WLR_SCENE_NODE_RECT:
|
||||||
|
|
@ -48,27 +49,30 @@ static void _get_scene_node_extents(struct wlr_scene_node *node, struct wlr_box
|
||||||
struct wlr_box node_box = { .x = lx, .y = ly };
|
struct wlr_box node_box = { .x = lx, .y = ly };
|
||||||
scene_node_get_size(node, &node_box.width, &node_box.height);
|
scene_node_get_size(node, &node_box.width, &node_box.height);
|
||||||
|
|
||||||
if (node_box.x < box->x) {
|
if (node_box.x < *x_min) {
|
||||||
box->x = node_box.x;
|
*x_min = node_box.x;
|
||||||
}
|
}
|
||||||
if (node_box.y < box->y) {
|
if (node_box.y < *y_min) {
|
||||||
box->y = node_box.y;
|
*y_min = node_box.y;
|
||||||
}
|
}
|
||||||
if (node_box.x + node_box.width > box->x + box->width) {
|
if (node_box.x + node_box.width > *x_max) {
|
||||||
box->width = node_box.x + node_box.width - box->x;
|
*x_max = node_box.x + node_box.width;
|
||||||
}
|
}
|
||||||
if (node_box.y + node_box.height > box->y + box->height) {
|
if (node_box.y + node_box.height > *y_max) {
|
||||||
box->height = node_box.y + node_box.height - box->y;
|
*y_max = node_box.y + node_box.height;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_scene_node_extents(struct wlr_scene_node *node, struct wlr_box *box) {
|
static void get_scene_node_extents(struct wlr_scene_node *node, struct wlr_box *box) {
|
||||||
*box = (struct wlr_box){ .x = INT_MAX, .y = INT_MAX };
|
|
||||||
int lx = 0, ly = 0;
|
int lx = 0, ly = 0;
|
||||||
wlr_scene_node_coords(node, &lx, &ly);
|
wlr_scene_node_coords(node, &lx, &ly);
|
||||||
_get_scene_node_extents(node, box, lx, ly);
|
*box = (struct wlr_box){ .x = INT_MAX, .y = INT_MAX };
|
||||||
|
int x_max = INT_MIN, y_max = INT_MIN;
|
||||||
|
_get_scene_node_extents(node, lx, ly, &box->x, &box->y, &x_max, &y_max);
|
||||||
|
box->width = x_max - box->x;
|
||||||
|
box->height = y_max - box->y;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void source_render(struct scene_node_source *source) {
|
static void source_render(struct scene_node_source *source) {
|
||||||
|
|
|
||||||
|
|
@ -159,9 +159,8 @@ static void output_cursor_update_visible(struct wlr_output_cursor *cursor) {
|
||||||
struct wlr_box cursor_box;
|
struct wlr_box cursor_box;
|
||||||
output_cursor_get_box(cursor, &cursor_box);
|
output_cursor_get_box(cursor, &cursor_box);
|
||||||
|
|
||||||
struct wlr_box intersection;
|
|
||||||
cursor->visible =
|
cursor->visible =
|
||||||
wlr_box_intersection(&intersection, &output_box, &cursor_box);
|
wlr_box_intersects(&output_box, &cursor_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool output_pick_cursor_format(struct wlr_output *output,
|
static bool output_pick_cursor_format(struct wlr_output *output,
|
||||||
|
|
|
||||||
|
|
@ -233,6 +233,11 @@ static void output_apply_state(struct wlr_output *output,
|
||||||
output->transform = state->transform;
|
output->transform = state->transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state->committed & WLR_OUTPUT_STATE_COLOR_REPRESENTATION) {
|
||||||
|
output->color_encoding = state->color_encoding;
|
||||||
|
output->color_range = state->color_range;
|
||||||
|
}
|
||||||
|
|
||||||
if (state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
|
if (state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
|
||||||
if (state->image_description != NULL) {
|
if (state->image_description != NULL) {
|
||||||
output->image_description_value = *state->image_description;
|
output->image_description_value = *state->image_description;
|
||||||
|
|
@ -580,6 +585,11 @@ static uint32_t output_compare_state(struct wlr_output *output,
|
||||||
output->color_transform == state->color_transform) {
|
output->color_transform == state->color_transform) {
|
||||||
fields |= WLR_OUTPUT_STATE_COLOR_TRANSFORM;
|
fields |= WLR_OUTPUT_STATE_COLOR_TRANSFORM;
|
||||||
}
|
}
|
||||||
|
if ((state->committed & WLR_OUTPUT_STATE_COLOR_REPRESENTATION) &&
|
||||||
|
output->color_encoding == state->color_encoding &&
|
||||||
|
output->color_range == state->color_range) {
|
||||||
|
fields |= WLR_OUTPUT_STATE_COLOR_REPRESENTATION;
|
||||||
|
}
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -615,7 +625,7 @@ static bool output_basic_test(struct wlr_output *output,
|
||||||
};
|
};
|
||||||
struct wlr_box dst_box;
|
struct wlr_box dst_box;
|
||||||
output_state_get_buffer_dst_box(state, &dst_box);
|
output_state_get_buffer_dst_box(state, &dst_box);
|
||||||
if (!wlr_box_intersection(&output_box, &output_box, &dst_box)) {
|
if (!wlr_box_intersects(&output_box, &dst_box)) {
|
||||||
wlr_log(WLR_ERROR, "Primary buffer is entirely off-screen or 0-sized");
|
wlr_log(WLR_ERROR, "Primary buffer is entirely off-screen or 0-sized");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -632,6 +642,10 @@ static bool output_basic_test(struct wlr_output *output,
|
||||||
wlr_log(WLR_DEBUG, "Tried to set signal timeline without a buffer");
|
wlr_log(WLR_DEBUG, "Tried to set signal timeline without a buffer");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (state->committed & WLR_OUTPUT_STATE_COLOR_REPRESENTATION) {
|
||||||
|
wlr_log(WLR_DEBUG, "Tried to set color representation without a buffer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) {
|
if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) {
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,14 @@ bool wlr_output_state_set_image_description(struct wlr_output_state *state,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wlr_output_state_set_color_encoding_and_range(
|
||||||
|
struct wlr_output_state *state,
|
||||||
|
enum wlr_color_encoding encoding, enum wlr_color_range range) {
|
||||||
|
state->committed |= WLR_OUTPUT_STATE_COLOR_REPRESENTATION;
|
||||||
|
state->color_encoding = encoding;
|
||||||
|
state->color_range = range;
|
||||||
|
}
|
||||||
|
|
||||||
bool wlr_output_state_copy(struct wlr_output_state *dst,
|
bool wlr_output_state_copy(struct wlr_output_state *dst,
|
||||||
const struct wlr_output_state *src) {
|
const struct wlr_output_state *src) {
|
||||||
struct wlr_output_state copy = *src;
|
struct wlr_output_state copy = *src;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,24 +113,11 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) {
|
||||||
if (node->type == WLR_SCENE_NODE_BUFFER) {
|
if (node->type == WLR_SCENE_NODE_BUFFER) {
|
||||||
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
|
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
|
||||||
|
|
||||||
uint64_t active = scene_buffer->active_outputs;
|
|
||||||
if (active) {
|
|
||||||
struct wlr_scene_output *scene_output;
|
|
||||||
wl_list_for_each(scene_output, &scene->outputs, link) {
|
|
||||||
if (active & (1ull << scene_output->index)) {
|
|
||||||
wl_signal_emit_mutable(&scene_buffer->events.output_leave,
|
|
||||||
scene_output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scene_buffer_set_buffer(scene_buffer, NULL);
|
scene_buffer_set_buffer(scene_buffer, NULL);
|
||||||
scene_buffer_set_texture(scene_buffer, NULL);
|
scene_buffer_set_texture(scene_buffer, NULL);
|
||||||
pixman_region32_fini(&scene_buffer->opaque_region);
|
pixman_region32_fini(&scene_buffer->opaque_region);
|
||||||
wlr_drm_syncobj_timeline_unref(scene_buffer->wait_timeline);
|
wlr_drm_syncobj_timeline_unref(scene_buffer->wait_timeline);
|
||||||
|
|
||||||
assert(wl_list_empty(&scene_buffer->events.output_leave.listener_list));
|
|
||||||
assert(wl_list_empty(&scene_buffer->events.output_enter.listener_list));
|
|
||||||
assert(wl_list_empty(&scene_buffer->events.outputs_update.listener_list));
|
assert(wl_list_empty(&scene_buffer->events.outputs_update.listener_list));
|
||||||
assert(wl_list_empty(&scene_buffer->events.output_sample.listener_list));
|
assert(wl_list_empty(&scene_buffer->events.output_sample.listener_list));
|
||||||
assert(wl_list_empty(&scene_buffer->events.frame_done.listener_list));
|
assert(wl_list_empty(&scene_buffer->events.frame_done.listener_list));
|
||||||
|
|
@ -238,7 +225,7 @@ static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box
|
||||||
struct wlr_box node_box = { .x = lx, .y = ly };
|
struct wlr_box node_box = { .x = lx, .y = ly };
|
||||||
scene_node_get_size(node, &node_box.width, &node_box.height);
|
scene_node_get_size(node, &node_box.width, &node_box.height);
|
||||||
|
|
||||||
if (wlr_box_intersection(&node_box, &node_box, box) &&
|
if (wlr_box_intersects(&node_box, box) &&
|
||||||
iterator(node, lx, ly, user_data)) {
|
iterator(node, lx, ly, user_data)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -481,28 +468,12 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
|
||||||
(struct wlr_linux_dmabuf_feedback_v1_init_options){0};
|
(struct wlr_linux_dmabuf_feedback_v1_init_options){0};
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t old_active = scene_buffer->active_outputs;
|
|
||||||
scene_buffer->active_outputs = active_outputs;
|
|
||||||
|
|
||||||
struct wlr_scene_output *scene_output;
|
|
||||||
wl_list_for_each(scene_output, outputs, link) {
|
|
||||||
uint64_t mask = 1ull << scene_output->index;
|
|
||||||
bool intersects = active_outputs & mask;
|
|
||||||
bool intersects_before = old_active & mask;
|
|
||||||
|
|
||||||
if (intersects && !intersects_before) {
|
|
||||||
wl_signal_emit_mutable(&scene_buffer->events.output_enter, scene_output);
|
|
||||||
} else if (!intersects && intersects_before) {
|
|
||||||
wl_signal_emit_mutable(&scene_buffer->events.output_leave, scene_output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there are active outputs on this node, we should always have a primary
|
// if there are active outputs on this node, we should always have a primary
|
||||||
// output
|
// output
|
||||||
assert(!scene_buffer->active_outputs || scene_buffer->primary_output);
|
assert(!active_outputs || scene_buffer->primary_output);
|
||||||
|
|
||||||
// Skip output update event if nothing was updated
|
// Skip output update event if nothing was updated
|
||||||
if (old_active == active_outputs &&
|
if (scene_buffer->active_outputs == active_outputs &&
|
||||||
(!force || ((1ull << force->index) & ~active_outputs)) &&
|
(!force || ((1ull << force->index) & ~active_outputs)) &&
|
||||||
old_primary_output == scene_buffer->primary_output) {
|
old_primary_output == scene_buffer->primary_output) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -515,6 +486,7 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
struct wlr_scene_output *scene_output;
|
||||||
wl_list_for_each(scene_output, outputs, link) {
|
wl_list_for_each(scene_output, outputs, link) {
|
||||||
if (~active_outputs & (1ull << scene_output->index)) {
|
if (~active_outputs & (1ull << scene_output->index)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -524,6 +496,7 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
|
||||||
outputs_array[i++] = scene_output;
|
outputs_array[i++] = scene_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scene_buffer->active_outputs = active_outputs;
|
||||||
wl_signal_emit_mutable(&scene_buffer->events.outputs_update, &event);
|
wl_signal_emit_mutable(&scene_buffer->events.outputs_update, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -869,8 +842,6 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
|
||||||
scene_node_init(&scene_buffer->node, WLR_SCENE_NODE_BUFFER, parent);
|
scene_node_init(&scene_buffer->node, WLR_SCENE_NODE_BUFFER, parent);
|
||||||
|
|
||||||
wl_signal_init(&scene_buffer->events.outputs_update);
|
wl_signal_init(&scene_buffer->events.outputs_update);
|
||||||
wl_signal_init(&scene_buffer->events.output_enter);
|
|
||||||
wl_signal_init(&scene_buffer->events.output_leave);
|
|
||||||
wl_signal_init(&scene_buffer->events.output_sample);
|
wl_signal_init(&scene_buffer->events.output_sample);
|
||||||
wl_signal_init(&scene_buffer->events.frame_done);
|
wl_signal_init(&scene_buffer->events.frame_done);
|
||||||
|
|
||||||
|
|
@ -1553,6 +1524,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 +1758,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 +1816,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);
|
||||||
|
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);
|
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);
|
||||||
|
|
@ -2086,15 +2069,6 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout(
|
||||||
return SCANOUT_INELIGIBLE;
|
return SCANOUT_INELIGIBLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_color_repr_none = buffer->color_encoding == WLR_COLOR_ENCODING_NONE &&
|
|
||||||
buffer->color_range == WLR_COLOR_RANGE_NONE;
|
|
||||||
bool is_color_repr_identity_full = buffer->color_encoding == WLR_COLOR_ENCODING_IDENTITY &&
|
|
||||||
buffer->color_range == WLR_COLOR_RANGE_FULL;
|
|
||||||
|
|
||||||
if (!(is_color_repr_none || is_color_repr_identity_full)) {
|
|
||||||
return SCANOUT_INELIGIBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want to ensure optimal buffer selection, but as direct-scanout can be enabled and disabled
|
// We want to ensure optimal buffer selection, but as direct-scanout can be enabled and disabled
|
||||||
// on a frame-by-frame basis, we wait for a few frames to send the new format recommendations.
|
// on a frame-by-frame basis, we wait for a few frames to send the new format recommendations.
|
||||||
// Maybe we should only send feedback in this case if tests fail.
|
// Maybe we should only send feedback in this case if tests fail.
|
||||||
|
|
@ -2136,6 +2110,23 @@ 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 (buffer->color_encoding == WLR_COLOR_ENCODING_IDENTITY &&
|
||||||
|
buffer->color_range == WLR_COLOR_RANGE_FULL) {
|
||||||
|
// IDENTITY+FULL (used for RGB formats) is equivalent to no color
|
||||||
|
// representation being set at all.
|
||||||
|
wlr_output_state_set_color_encoding_and_range(&pending,
|
||||||
|
WLR_COLOR_ENCODING_NONE, WLR_COLOR_RANGE_NONE);
|
||||||
|
} else {
|
||||||
|
wlr_output_state_set_color_encoding_and_range(&pending,
|
||||||
|
buffer->color_encoding, buffer->color_range);
|
||||||
|
}
|
||||||
|
|
||||||
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 +2138,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 +2599,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) {
|
||||||
|
|
@ -2673,8 +2669,7 @@ static void scene_output_for_each_scene_buffer(const struct wlr_box *output_box,
|
||||||
struct wlr_box node_box = { .x = lx, .y = ly };
|
struct wlr_box node_box = { .x = lx, .y = ly };
|
||||||
scene_node_get_size(node, &node_box.width, &node_box.height);
|
scene_node_get_size(node, &node_box.width, &node_box.height);
|
||||||
|
|
||||||
struct wlr_box intersection;
|
if (wlr_box_intersects(output_box, &node_box)) {
|
||||||
if (wlr_box_intersection(&intersection, output_box, &node_box)) {
|
|
||||||
struct wlr_scene_buffer *scene_buffer =
|
struct wlr_scene_buffer *scene_buffer =
|
||||||
wlr_scene_buffer_from_node(node);
|
wlr_scene_buffer_from_node(node);
|
||||||
user_iterator(scene_buffer, lx, ly, user_data);
|
user_iterator(scene_buffer, lx, ly, user_data);
|
||||||
|
|
|
||||||
|
|
@ -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,8 +1037,13 @@ 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 ||
|
||||||
|
img_desc_data_equal(&surface_feedback->data, data)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
surface_feedback->data = *data;
|
surface_feedback->data = *data;
|
||||||
|
|
||||||
uint32_t version = wl_resource_get_version(surface_feedback->resource);
|
uint32_t version = wl_resource_get_version(surface_feedback->resource);
|
||||||
if (version >= WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_PREFERRED_CHANGED2_SINCE_VERSION) {
|
if (version >= WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_PREFERRED_CHANGED2_SINCE_VERSION) {
|
||||||
wp_color_management_surface_feedback_v1_send_preferred_changed2(
|
wp_color_management_surface_feedback_v1_send_preferred_changed2(
|
||||||
|
|
@ -1013,7 +1053,6 @@ void wlr_color_manager_v1_set_surface_preferred_image_description(
|
||||||
surface_feedback->resource, identity_lo);
|
surface_feedback->resource, identity_lo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum wlr_color_transfer_function
|
enum wlr_color_transfer_function
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -260,14 +260,12 @@ bool wlr_output_layout_contains_point(struct wlr_output_layout *layout,
|
||||||
|
|
||||||
bool wlr_output_layout_intersects(struct wlr_output_layout *layout,
|
bool wlr_output_layout_intersects(struct wlr_output_layout *layout,
|
||||||
struct wlr_output *reference, const struct wlr_box *target_lbox) {
|
struct wlr_output *reference, const struct wlr_box *target_lbox) {
|
||||||
struct wlr_box out_box;
|
|
||||||
|
|
||||||
if (reference == NULL) {
|
if (reference == NULL) {
|
||||||
struct wlr_output_layout_output *l_output;
|
struct wlr_output_layout_output *l_output;
|
||||||
wl_list_for_each(l_output, &layout->outputs, link) {
|
wl_list_for_each(l_output, &layout->outputs, link) {
|
||||||
struct wlr_box output_box;
|
struct wlr_box output_box;
|
||||||
output_layout_output_get_box(l_output, &output_box);
|
output_layout_output_get_box(l_output, &output_box);
|
||||||
if (wlr_box_intersection(&out_box, &output_box, target_lbox)) {
|
if (wlr_box_intersects(&output_box, target_lbox)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -281,7 +279,7 @@ bool wlr_output_layout_intersects(struct wlr_output_layout *layout,
|
||||||
|
|
||||||
struct wlr_box output_box;
|
struct wlr_box output_box;
|
||||||
output_layout_output_get_box(l_output, &output_box);
|
output_layout_output_get_box(l_output, &output_box);
|
||||||
return wlr_box_intersection(&out_box, &output_box, target_lbox);
|
return wlr_box_intersects(&output_box, target_lbox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
25
util/box.c
25
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;
|
||||||
|
|
@ -94,6 +102,15 @@ bool wlr_box_contains_box(const struct wlr_box *bigger, const struct wlr_box *sm
|
||||||
smaller->y + smaller->height <= bigger->y + bigger->height;
|
smaller->y + smaller->height <= bigger->y + bigger->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wlr_box_intersects(const struct wlr_box *a, const struct wlr_box *b) {
|
||||||
|
if (wlr_box_empty(a) || wlr_box_empty(b)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a->x < b->x + b->width && b->x < a->x + a->width &&
|
||||||
|
a->y < b->y + b->height && b->y < a->y + a->height;
|
||||||
|
}
|
||||||
|
|
||||||
void wlr_box_transform(struct wlr_box *dest, const struct wlr_box *box,
|
void wlr_box_transform(struct wlr_box *dest, const struct wlr_box *box,
|
||||||
enum wl_output_transform transform, int width, int height) {
|
enum wl_output_transform transform, int width, int height) {
|
||||||
struct wlr_box src = {0};
|
struct wlr_box src = {0};
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,7 @@ struct x11_data_source {
|
||||||
static const struct wlr_data_source_impl data_source_impl;
|
static const struct wlr_data_source_impl data_source_impl;
|
||||||
|
|
||||||
bool data_source_is_xwayland(
|
bool data_source_is_xwayland(
|
||||||
struct wlr_data_source *wlr_source) {
|
const struct wlr_data_source *wlr_source) {
|
||||||
return wlr_source->impl == &data_source_impl;
|
return wlr_source->impl == &data_source_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -292,7 +292,7 @@ static const struct wlr_primary_selection_source_impl
|
||||||
primary_selection_source_impl;
|
primary_selection_source_impl;
|
||||||
|
|
||||||
bool primary_selection_source_is_xwayland(
|
bool primary_selection_source_is_xwayland(
|
||||||
struct wlr_primary_selection_source *wlr_source) {
|
const struct wlr_primary_selection_source *wlr_source) {
|
||||||
return wlr_source->impl == &primary_selection_source_impl;
|
return wlr_source->impl == &primary_selection_source_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue