Compare commits

..

24 commits

Author SHA1 Message Date
Simon Ser
c1d38536c9 build: bump version to 0.20.0 2026-03-26 17:38:50 +01:00
Simon Zeni
a945fd8940 render/vulkan: compile against vulkan 1.2 header
Uses the EXT version of VK_PIPELINE_COMPILE_REQUIRED in `vulkan_strerror` func since it requires
Vulkan 1.3, switch to VK_EXT_global_priority instead of VK_KHR_global_priority which is only
promoted to core in Vulkan 1.3 as well.

(cherry picked from commit 413664e0b0)
2026-03-26 17:38:25 +01:00
Félix Poisot
2bfbec4af1 linux_drm_syncobj_v1: fix handling of empty first commit
As reported in
https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4979#note_3385626,
bfd6e619fc did not correctly handle clients
that don't immediately follow their call to
`wp_linux_drm_syncobj_manager_v1.get_surface` with a commit attaching
a buffer

Fixes: bfd6e619fc
(cherry picked from commit fd870f6d27)
2026-03-26 17:38:25 +01:00
Simon Ser
1a9b1292e2 color_management_v1: ignore surface update if no-op
If the new image description is identical to the old one, skip the
event.

(cherry picked from commit 4ca40004fd)
2026-03-26 17:38:25 +01:00
Simon Ser
ad82740518 color_management_v1: use early continue in surface loop
(cherry picked from commit 7287f700ab)
2026-03-26 17:38:25 +01:00
Simon Ser
bba38a0d82 build: bump version to 0.20.0-rc5 2026-03-19 20:02:25 +01:00
Félix Poisot
df1539d9f0 output/drm: don't use OUT_FENCE_PTR
The returned fence is not required to be signalled at the earliest
possible time. It is not intended to replace the drm flip event, and is
expected to be signalled only much later

(cherry picked from commit 8d454e1e34)
2026-03-19 20:01:40 +01:00
Félix Poisot
eff5aa52e6 backend/drm: properly delay syncobj signalling
DRM CRTC signals when scanout begins, but
wlr_output_state_set_signal_timeline() is defined to signal buffer
release. Delay to the next page flip

(cherry picked from commit cd555f9261)
2026-03-19 20:01:40 +01:00
Félix Poisot
8daba3246d scene: transfer sample syncobj to client timeline
(cherry picked from commit b2f6a390a4)
2026-03-19 20:01:40 +01:00
Félix Poisot
52564ea97c linux_drm_syncobj_v1: add release point accumulation
This changes the behavior of wlr_linux_drm_syncobj_surface_v1 to
automatically signal release of previous commits as they are replaced.

Users must call wlr_linux_drm_syncobj_v1_state_add_release_point or
wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer to delay the
signal as appropriate.

(cherry picked from commit bfd6e619fc)
2026-03-19 20:01:40 +01:00
Félix Poisot
288ba9e75b drm/syncobj: add timeline point merger utility
(cherry picked from commit e83a679e23)
2026-03-19 20:01:40 +01:00
Félix Poisot
2f14845ce0 scene: add buffer release point to 'sample' event
(cherry picked from commit 1f3d351abb)
2026-03-19 20:01:23 +01:00
Félix Poisot
c4ff394f7f render/drm_syncobj: add wlr_drm_syncobj_timeline_signal()
(cherry picked from commit 0af9b9d003)
2026-03-19 19:48:36 +01:00
Isaac Freund
88718e84c9 virtual-keyboard: handle seat destroy
We must make the virtual keyboard inert when the seat is destroyed.

(cherry picked from commit 1fa8bb8f7a)
2026-03-19 19:48:14 +01:00
Isaac Freund
6a902237ef virtual-keyboard: add wlr_virtual_keyboard_v1_from_resource()
I want to use the zwp_virtual_keyboard_v1 object in a custom river
protocol and need to be able to obtain the corresponding wlroots struct.

(cherry picked from commit ec746d3e3e)
2026-03-19 19:48:14 +01:00
Scott Moreau
47a43e14ae wlr_ext_image_copy_capture_v1: Fix crash when client creates a cursor session not implemented server side
This guards against a crash where the server implements
wlr_ext_image_capture_source_v1_interface without setting .get_pointer_cursor().
In general, we should install a NULL check here because this is a crash
waiting to happen. Now, instead of crashing, the resource will be created and
the copy capture session will be stopped.

(cherry picked from commit 1fc928d528)
2026-03-19 19:48:09 +01:00
llyyr
ba32abbddb scene: use wl_list_for_each_safe to iterate outputs
The outputs loop in handle_scene_buffer_outputs_update may remove entries
from the list while iterating, so use wl_list_for_each_safe instead of
wl_list_for_each.

Fixes: 39e918edc8 ("scene: avoid redundant wl_surface.enter/leave events")
(cherry picked from commit 3cb2cf9425)
2026-03-19 19:48:05 +01:00
Isaac Freund
9c3bfbeb48 scene: avoid redundant wl_surface.enter/leave events
Currently we send wl_surface.enter/leave when a surface is hidden
and shown again on the same output. In practice, this happens very
often since compositors like river and sway enable and disable
the scene nodes of surfaces as part of their atomic transaction
strategy involving rendering saved buffers while waiting for
clients to submit new buffers of the desired size.

The new strategy documented in the new comments avoids sending
redundant events in this case.

(cherry picked from commit 39e918edc8)
2026-03-19 19:47:55 +01:00
Diego Viola
b727521449 wlr-export-dmabuf-unstable-v1: fix typo
(cherry picked from commit 736c0f3f25)
2026-03-19 19:47:55 +01:00
Jonathan Marler
af228b879a backend/x11: ignore DestroyNotify events
The X11 backend subscribes to StructureNotify events, so when
output_destroy() calls xcb_destroy_window() the server sends a
DestroyNotify back. This is expected and harmless but was logged
as an unhandled event. Silence it the same way MAP_NOTIFY and
UNMAP_NOTIFY are already silenced.

(cherry picked from commit 3c8d199ec1)
2026-03-19 19:47:55 +01:00
Kenny Levinsen
ec26eb250a util/box: Use integer min/max for intersection
wlr_box_intersection only operates on integers, so we shouldn't use
fmin/fmax. Do the usual and add a local integer min/max helper.

(cherry picked from commit 285cee5f3a)
2026-03-19 19:47:55 +01:00
Christopher Snowhill
3105ac2b16 scene: fix color format compare
bool doesn't really support negative values.

Fixes: 7cb3393e7 (scene: send color_management_v1 surface feedback)
(cherry picked from commit 9a931d9ffa)
2026-03-19 19:47:55 +01:00
Simon Zeni
557fde4d01 ci: update dalligi upstream repo
(cherry picked from commit 67ce318b1f)
2026-03-19 19:47:55 +01:00
Andri Yngvason
e444836bf2 image_capture_source/output: Update constraints on enable
Without observing the enable event, clients receive no pixel formats and
buffer dimensions are reported as 0 after an output has been re-enabled.

(cherry picked from commit 3336d28813)
2026-03-19 19:47:55 +01:00
54 changed files with 204 additions and 690 deletions

View file

@ -35,9 +35,6 @@ tasks:
cd wlroots
ninja -C build
sudo ninja -C build install
- test: |
cd wlroots
meson test -C build --verbose
- build-features-disabled: |
cd wlroots
meson setup build --reconfigure -Dauto_features=disabled

View file

@ -37,10 +37,6 @@ tasks:
- clang: |
cd wlroots/build-clang
ninja
- test: |
cd wlroots/build-gcc
meson test --verbose
meson test --benchmark --verbose
- smoke-test: |
cd wlroots/build-gcc/tinywl
sudo modprobe vkms

View file

@ -32,9 +32,6 @@ tasks:
meson setup build --fatal-meson-warnings -Dauto_features=enabled -Dallocators=gbm
ninja -C build
sudo ninja -C build install
- test: |
cd wlroots
meson test -C build --verbose
- tinywl: |
cd wlroots/tinywl
make

View file

@ -1,4 +1,3 @@
#include <assert.h>
#include <drm_fourcc.h>
#include <stdlib.h>
#include <stdio.h>
@ -476,62 +475,6 @@ static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm,
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) {
return plane->props.hotspot_x && plane->props.hotspot_y;
}
@ -585,10 +528,6 @@ static void atomic_connector_add(struct atomic *atom,
set_plane_props(atom, drm, crtc->primary, state->primary_fb, crtc->id,
&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) {
atomic_add(atom, crtc->primary->id,
crtc->primary->props.fb_damage_clips, state->fb_damage_clips);

View file

@ -95,7 +95,7 @@ static const struct wlr_backend_impl backend_impl = {
.commit = backend_commit,
};
bool wlr_backend_is_drm(const struct wlr_backend *b) {
bool wlr_backend_is_drm(struct wlr_backend *b) {
return b->impl == &backend_impl;
}

View file

@ -43,8 +43,7 @@ static const uint32_t COMMIT_OUTPUT_STATE =
WLR_OUTPUT_STATE_WAIT_TIMELINE |
WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
WLR_OUTPUT_STATE_COLOR_TRANSFORM |
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION |
WLR_OUTPUT_STATE_COLOR_REPRESENTATION;
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION;
static const uint32_t SUPPORTED_OUTPUT_STATE =
WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE;
@ -1321,7 +1320,7 @@ static const struct wlr_output_impl output_impl = {
.get_primary_formats = drm_connector_get_primary_formats,
};
bool wlr_output_is_drm(const struct wlr_output *output) {
bool wlr_output_is_drm(struct wlr_output *output) {
return output->impl == &output_impl;
}

View file

@ -50,8 +50,6 @@ static const struct prop_info crtc_info[] = {
static const struct prop_info plane_info[] = {
#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_ID", INDEX(crtc_id) },
{ "CRTC_W", INDEX(crtc_w) },

View file

@ -81,6 +81,6 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_event_loop *loop) {
return &backend->backend;
}
bool wlr_backend_is_headless(const struct wlr_backend *backend) {
bool wlr_backend_is_headless(struct wlr_backend *backend) {
return backend->impl == &backend_impl;
}

View file

@ -106,7 +106,7 @@ static const struct wlr_output_impl output_impl = {
.move_cursor = output_move_cursor,
};
bool wlr_output_is_headless(const struct wlr_output *wlr_output) {
bool wlr_output_is_headless(struct wlr_output *wlr_output) {
return wlr_output->impl == &output_impl;
}

View file

@ -155,7 +155,7 @@ static const struct wlr_backend_impl backend_impl = {
.destroy = backend_destroy,
};
bool wlr_backend_is_libinput(const struct wlr_backend *b) {
bool wlr_backend_is_libinput(struct wlr_backend *b) {
return b->impl == &backend_impl;
}

View file

@ -173,7 +173,7 @@ struct wlr_backend *wlr_multi_backend_create(struct wl_event_loop *loop) {
return &backend->backend;
}
bool wlr_backend_is_multi(const struct wlr_backend *b) {
bool wlr_backend_is_multi(struct wlr_backend *b) {
return b->impl == &backend_impl;
}

View file

@ -577,7 +577,7 @@ static const struct wlr_backend_impl backend_impl = {
.get_drm_fd = backend_get_drm_fd,
};
bool wlr_backend_is_wl(const struct wlr_backend *b) {
bool wlr_backend_is_wl(struct wlr_backend *b) {
return b->impl == &backend_impl;
}

View file

@ -1027,7 +1027,7 @@ static const struct wlr_output_impl output_impl = {
.get_primary_formats = output_get_formats,
};
bool wlr_output_is_wl(const struct wlr_output *wlr_output) {
bool wlr_output_is_wl(struct wlr_output *wlr_output) {
return wlr_output->impl == &output_impl;
}

View file

@ -219,7 +219,7 @@ static const struct wlr_backend_impl backend_impl = {
.get_drm_fd = backend_get_drm_fd,
};
bool wlr_backend_is_x11(const struct wlr_backend *backend) {
bool wlr_backend_is_x11(struct wlr_backend *backend) {
return backend->impl == &backend_impl;
}

View file

@ -711,7 +711,7 @@ void handle_x11_configure_notify(struct wlr_x11_output *output,
wlr_output_state_finish(&state);
}
bool wlr_output_is_x11(const struct wlr_output *wlr_output) {
bool wlr_output_is_x11(struct wlr_output *wlr_output) {
return wlr_output->impl == &output_impl;
}

View file

@ -65,22 +65,6 @@ struct wlr_drm_plane_props {
uint32_t hotspot_x;
uint32_t hotspot_y;
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,

View file

@ -56,10 +56,6 @@ struct wlr_vk_device {
PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR;
PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR;
PFN_vkQueueSubmit2KHR vkQueueSubmit2KHR;
PFN_vkBindImageMemory2KHR vkBindImageMemory2KHR;
PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR;
PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR;
PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR;
} api;
uint32_t format_prop_count;
@ -410,7 +406,7 @@ VkCommandBuffer vulkan_record_stage_cb(struct wlr_vk_renderer *renderer);
// Submits the current stage command buffer and waits until it has
// finished execution.
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer, int wait_sync_file_fd);
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer);
struct wlr_vk_render_pass_texture {
struct wlr_vk_texture *texture;
@ -476,8 +472,6 @@ uint64_t vulkan_end_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,
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,
struct wlr_vk_render_pass *pass);
@ -490,8 +484,7 @@ bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,
VkFormat src_format, VkImage src_image,
uint32_t drm_format, uint32_t stride,
uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y,
uint32_t dst_x, uint32_t dst_y, void *data,
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point);
uint32_t dst_x, uint32_t dst_y, void *data);
// State (e.g. image texture) associated with a surface.
struct wlr_vk_texture {

View file

@ -39,8 +39,8 @@ struct wlr_drm_lease {
struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
struct wlr_device *dev, struct wlr_backend *parent);
bool wlr_backend_is_drm(const struct wlr_backend *backend);
bool wlr_output_is_drm(const struct wlr_output *output);
bool wlr_backend_is_drm(struct wlr_backend *backend);
bool wlr_output_is_drm(struct wlr_output *output);
/**
* Get the parent DRM backend, if any.

View file

@ -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,
unsigned int width, unsigned int height);
bool wlr_backend_is_headless(const struct wlr_backend *backend);
bool wlr_output_is_headless(const struct wlr_output *output);
bool wlr_backend_is_headless(struct wlr_backend *backend);
bool wlr_output_is_headless(struct wlr_output *output);
#endif

View file

@ -29,7 +29,7 @@ struct libinput_device *wlr_libinput_get_device_handle(
struct libinput_tablet_tool *wlr_libinput_get_tablet_tool_handle(
struct wlr_tablet_tool *wlr_tablet_tool);
bool wlr_backend_is_libinput(const struct wlr_backend *backend);
bool wlr_backend_is_libinput(struct wlr_backend *backend);
bool wlr_input_device_is_libinput(struct wlr_input_device *device);
#endif

View file

@ -26,7 +26,7 @@ bool wlr_multi_backend_add(struct wlr_backend *multi,
void wlr_multi_backend_remove(struct wlr_backend *multi,
struct wlr_backend *backend);
bool wlr_backend_is_multi(const struct wlr_backend *backend);
bool wlr_backend_is_multi(struct wlr_backend *backend);
bool wlr_multi_is_empty(struct wlr_backend *backend);
void wlr_multi_for_each_backend(struct wlr_backend *backend,

View file

@ -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.
*/
bool wlr_backend_is_wl(const struct wlr_backend *backend);
bool wlr_backend_is_wl(struct wlr_backend *backend);
/**
* 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.
*/
bool wlr_output_is_wl(const struct wlr_output *output);
bool wlr_output_is_wl(struct wlr_output *output);
/**
* Sets the title of a struct wlr_output which is a Wayland toplevel.

View file

@ -31,7 +31,7 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend);
/**
* Check whether this backend is an X11 backend.
*/
bool wlr_backend_is_x11(const struct wlr_backend *backend);
bool wlr_backend_is_x11(struct wlr_backend *backend);
/**
* 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.
*/
bool wlr_output_is_x11(const struct wlr_output *output);
bool wlr_output_is_x11(struct wlr_output *output);
/**
* Sets the title of a struct wlr_output which is an X11 window.

View file

@ -97,11 +97,7 @@ bool wlr_drm_syncobj_timeline_signal(struct wlr_drm_syncobj_timeline *timeline,
/**
* Asynchronously wait for a timeline point.
*
* 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
* See wlr_drm_syncobj_timeline_check() for a definition of flags.
*
* A callback must be provided that will be invoked when the waiter has finished.
*/

View file

@ -42,9 +42,9 @@ struct wlr_gles2_texture_attribs {
bool has_alpha;
};
bool wlr_renderer_is_gles2(const struct wlr_renderer *wlr_renderer);
bool wlr_render_timer_is_gles2(const struct wlr_render_timer *timer);
bool wlr_texture_is_gles2(const struct wlr_texture *texture);
bool wlr_renderer_is_gles2(struct wlr_renderer *wlr_renderer);
bool wlr_render_timer_is_gles2(struct wlr_render_timer *timer);
bool wlr_texture_is_gles2(struct wlr_texture *texture);
void wlr_gles2_texture_get_attribs(struct wlr_texture *texture,
struct wlr_gles2_texture_attribs *attribs);

View file

@ -14,8 +14,8 @@
struct wlr_renderer *wlr_pixman_renderer_create(void);
bool wlr_renderer_is_pixman(const struct wlr_renderer *wlr_renderer);
bool wlr_texture_is_pixman(const struct wlr_texture *texture);
bool wlr_renderer_is_pixman(struct wlr_renderer *wlr_renderer);
bool wlr_texture_is_pixman(struct wlr_texture *texture);
pixman_image_t *wlr_pixman_renderer_get_buffer_image(
struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer);

View file

@ -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);
uint32_t wlr_vk_renderer_get_queue_family(struct wlr_renderer *renderer);
bool wlr_renderer_is_vk(const struct wlr_renderer *wlr_renderer);
bool wlr_texture_is_vk(const struct wlr_texture *texture);
bool wlr_renderer_is_vk(struct wlr_renderer *wlr_renderer);
bool wlr_texture_is_vk(struct wlr_texture *texture);
void wlr_vk_texture_get_image_attribs(struct wlr_texture *texture,
struct wlr_vk_image_attribs *attribs);

View file

@ -37,8 +37,6 @@ struct wlr_texture_read_pixels_options {
uint32_t dst_x, dst_y;
/** Source box of the texture to read from. If empty, the full texture is assumed. */
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,

View file

@ -77,7 +77,6 @@ enum wlr_output_state_field {
WLR_OUTPUT_STATE_SIGNAL_TIMELINE = 1 << 11,
WLR_OUTPUT_STATE_COLOR_TRANSFORM = 1 << 12,
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION = 1 << 13,
WLR_OUTPUT_STATE_COLOR_REPRESENTATION = 1 << 14,
};
enum wlr_output_state_mode_type {
@ -143,10 +142,6 @@ struct wlr_output_state {
* regular page-flip at the next wlr_output.frame event. */
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;
struct wlr_output_mode *mode;
struct {
@ -210,8 +205,6 @@ struct wlr_output {
enum wl_output_transform transform;
enum wlr_output_adaptive_sync_status adaptive_sync_status;
uint32_t render_format;
enum wlr_color_encoding color_encoding;
enum wlr_color_range color_range;
const struct wlr_output_image_description *image_description;
// Indicates whether making changes to adaptive sync status is supported.
@ -632,15 +625,6 @@ void wlr_output_state_set_color_transform(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);
/**
* 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
* wlr_output_state_finish() src and have dst still be valid.

View file

@ -171,6 +171,8 @@ struct wlr_scene_buffer {
struct {
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 frame_done; // struct wlr_scene_frame_done_event
} events;

View file

@ -107,13 +107,6 @@ void wlr_fbox_transform(struct wlr_fbox *dest, const struct wlr_fbox *box,
#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.
*/

View file

@ -82,9 +82,9 @@ void xwm_handle_selection_notify(struct wlr_xwm *xwm,
xcb_selection_notify_event_t *event);
int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm,
xcb_xfixes_selection_notify_event_t *event);
bool data_source_is_xwayland(const struct wlr_data_source *wlr_source);
bool data_source_is_xwayland(struct wlr_data_source *wlr_source);
bool primary_selection_source_is_xwayland(
const struct wlr_primary_selection_source *wlr_source);
struct wlr_primary_selection_source *wlr_source);
void xwm_seat_handle_start_drag(struct wlr_xwm *xwm, struct wlr_drag *drag);

View file

@ -1,7 +1,7 @@
project(
'wlroots',
'c',
version: '0.21.0-dev',
version: '0.20.0',
license: 'MIT',
meson_version: '>=1.3',
default_options: [
@ -178,10 +178,6 @@ if get_option('examples')
subdir('tinywl')
endif
if get_option('tests')
subdir('test')
endif
pkgconfig = import('pkgconfig')
pkgconfig.generate(
lib_wlr,

View file

@ -7,6 +7,5 @@ option('backends', type: 'array', choices: ['auto', 'drm', 'libinput', 'x11'], v
option('allocators', type: 'array', choices: ['auto', 'gbm', 'udmabuf'], value: ['auto'],
description: 'Select built-in allocators')
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('libliftoff', type: 'feature', value: 'auto', description: 'Enable support for libliftoff')

View file

@ -222,8 +222,14 @@ bool wlr_drm_syncobj_timeline_waiter_init(struct wlr_drm_syncobj_timeline_waiter
return false;
}
if (drmSyncobjEventfd(timeline->drm_fd, timeline->handle, point, ev_fd, flags) != 0) {
wlr_log_errno(WLR_ERROR, "drmSyncobjEventfd() failed");
struct drm_syncobj_eventfd syncobj_eventfd = {
.handle = timeline->handle,
.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);
return false;
}

View file

@ -29,7 +29,7 @@
static const struct wlr_renderer_impl renderer_impl;
static const struct wlr_render_timer_impl render_timer_impl;
bool wlr_renderer_is_gles2(const struct wlr_renderer *wlr_renderer) {
bool wlr_renderer_is_gles2(struct wlr_renderer *wlr_renderer) {
return wlr_renderer->impl == &renderer_impl;
}
@ -40,7 +40,7 @@ struct wlr_gles2_renderer *gles2_get_renderer(
return renderer;
}
bool wlr_render_timer_is_gles2(const struct wlr_render_timer *timer) {
bool wlr_render_timer_is_gles2(struct wlr_render_timer *timer) {
return timer->impl == &render_timer_impl;
}

View file

@ -4,10 +4,8 @@
#include <GLES2/gl2ext.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <wayland-server-protocol.h>
#include <wayland-util.h>
#include <wlr/render/drm_syncobj.h>
#include <wlr/render/egl.h>
#include <wlr/render/interface.h>
#include <wlr/render/wlr_texture.h>
@ -18,7 +16,7 @@
static const struct wlr_texture_impl texture_impl;
bool wlr_texture_is_gles2(const struct wlr_texture *wlr_texture) {
bool wlr_texture_is_gles2(struct wlr_texture *wlr_texture) {
return wlr_texture->impl == &texture_impl;
}
@ -203,27 +201,6 @@ static bool gles2_texture_read_pixels(struct wlr_texture *wlr_texture,
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
glFinish();

View file

@ -12,7 +12,7 @@
static const struct wlr_renderer_impl renderer_impl;
bool wlr_renderer_is_pixman(const struct wlr_renderer *wlr_renderer) {
bool wlr_renderer_is_pixman(struct wlr_renderer *wlr_renderer) {
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;
bool wlr_texture_is_pixman(const struct wlr_texture *texture) {
bool wlr_texture_is_pixman(struct wlr_texture *texture) {
return texture->impl == &texture_impl;
}

View file

@ -99,6 +99,53 @@ static void render_pass_destroy(struct wlr_vk_render_pass *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,
VkSemaphoreSubmitInfoKHR *render_wait, uint32_t *render_wait_len_ptr) {
int sync_file_fds[WLR_DMABUF_MAX_PLANES];
@ -115,8 +162,7 @@ static bool render_pass_wait_render_buffer(struct wlr_vk_render_pass *pass,
continue;
}
VkSemaphore sem = vulkan_command_buffer_wait_sync_file(pass->renderer,
pass->command_buffer, *render_wait_len_ptr, sync_file_fds[i]);
VkSemaphore sem = render_pass_wait_sync_file(pass, *render_wait_len_ptr, sync_file_fds[i]);
if (sem == VK_NULL_HANDLE) {
close(sync_file_fds[i]);
continue;
@ -385,8 +431,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
continue;
}
VkSemaphore sem = vulkan_command_buffer_wait_sync_file(renderer, render_cb,
render_wait_len, sync_file_fds[i]);
VkSemaphore sem = render_pass_wait_sync_file(pass, render_wait_len, sync_file_fds[i]);
if (sem == VK_NULL_HANDLE) {
close(sync_file_fds[i]);
continue;

View file

@ -46,7 +46,7 @@ static bool default_debug = true;
static const struct wlr_renderer_impl renderer_impl;
bool wlr_renderer_is_vk(const struct wlr_renderer *wlr_renderer) {
bool wlr_renderer_is_vk(struct wlr_renderer *wlr_renderer) {
return wlr_renderer->impl == &renderer_impl;
}
@ -379,52 +379,7 @@ VkCommandBuffer vulkan_record_stage_cb(struct wlr_vk_renderer *renderer) {
return renderer->stage.cb->vk;
}
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) {
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer) {
if (renderer->stage.cb == NULL) {
return false;
}
@ -434,12 +389,9 @@ bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer, int wait_sync_fi
uint64_t timeline_point = vulkan_end_command_buffer(cb, renderer);
if (timeline_point == 0) {
close(wait_sync_file_fd);
return false;
}
VkSemaphore wait_semaphore;
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
VkTimelineSemaphoreSubmitInfoKHR timeline_submit_info = {
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR,
.signalSemaphoreValueCount = 1,
@ -453,18 +405,6 @@ bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer, int wait_sync_fi
.signalSemaphoreCount = 1,
.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);
if (res != VK_SUCCESS) {
wlr_vk_error("vkQueueSubmit", res);
@ -1248,7 +1188,7 @@ static void vulkan_destroy(struct wlr_renderer *wlr_renderer) {
vkDestroyPipelineLayout(dev->dev, pipeline_layout->vk, NULL);
vkDestroyDescriptorSetLayout(dev->dev, pipeline_layout->ds, NULL);
vkDestroySampler(dev->dev, pipeline_layout->sampler, NULL);
renderer->dev->api.vkDestroySamplerYcbcrConversionKHR(dev->dev, pipeline_layout->ycbcr.conversion, NULL);
vkDestroySamplerYcbcrConversion(dev->dev, pipeline_layout->ycbcr.conversion, NULL);
free(pipeline_layout);
}
@ -1278,8 +1218,7 @@ bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,
VkFormat src_format, VkImage src_image,
uint32_t drm_format, uint32_t stride,
uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y,
uint32_t dst_x, uint32_t dst_y, void *data,
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point) {
uint32_t dst_x, uint32_t dst_y, void *data) {
VkDevice dev = vk_renderer->dev->dev;
const struct wlr_pixel_format_info *pixel_format_info = drm_get_pixel_format_info(drm_format);
@ -1465,17 +1404,7 @@ bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_MEMORY_READ_BIT);
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);
if (!vulkan_submit_stage_wait(vk_renderer)) {
return false;
}
@ -2120,10 +2049,10 @@ struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout(
.yChromaOffset = VK_CHROMA_LOCATION_MIDPOINT,
.chromaFilter = VK_FILTER_LINEAR,
};
res = renderer->dev->api.vkCreateSamplerYcbcrConversionKHR(renderer->dev->dev,
res = vkCreateSamplerYcbcrConversion(renderer->dev->dev,
&conversion_create_info, NULL, &pipeline_layout->ycbcr.conversion);
if (res != VK_SUCCESS) {
wlr_vk_error("vkCreateSamplerYcbcrConversionKHR", res);
wlr_vk_error("vkCreateSamplerYcbcrConversion", res);
free(pipeline_layout);
return NULL;
}

View file

@ -15,7 +15,7 @@
static const struct wlr_texture_impl texture_impl;
bool wlr_texture_is_vk(const struct wlr_texture *wlr_texture) {
bool wlr_texture_is_vk(struct wlr_texture *wlr_texture) {
return wlr_texture->impl == &texture_impl;
}
@ -238,8 +238,7 @@ static bool vulkan_texture_read_pixels(struct wlr_texture *wlr_texture,
void *p = wlr_texture_read_pixel_options_get_data(options);
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->wait_timeline, options->wait_point);
options->format, options->stride, src.width, src.height, src.x, src.y, 0, 0, p);
}
static uint32_t vulkan_texture_preferred_read_format(struct wlr_texture *wlr_texture) {
@ -654,7 +653,7 @@ VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer,
.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
};
renderer->dev->api.vkGetImageMemoryRequirements2KHR(dev, &memri, &memr);
vkGetImageMemoryRequirements2(dev, &memri, &memr);
int mem = vulkan_find_mem_type(renderer->dev, 0,
memr.memoryRequirements.memoryTypeBits & fdp.memoryTypeBits);
if (mem < 0) {
@ -713,7 +712,7 @@ VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer,
}
}
res = renderer->dev->api.vkBindImageMemory2KHR(dev, mem_count, bindi);
res = vkBindImageMemory2(dev, mem_count, bindi);
if (res != VK_SUCCESS) {
wlr_vk_error("vkBindMemory failed", res);
goto error_image;

View file

@ -81,6 +81,21 @@ static VKAPI_ATTR VkBool32 debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT
}
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;
VkResult res;
@ -110,18 +125,7 @@ struct wlr_vk_instance *vulkan_instance_create(bool debug) {
}
size_t extensions_len = 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;
}
}
const char *extensions[1] = {0};
bool debug_utils_found = false;
if (debug && check_extension(avail_ext_props, avail_extc,
@ -136,7 +140,7 @@ struct wlr_vk_instance *vulkan_instance_create(bool debug) {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pEngineName = "wlroots",
.engineVersion = WLR_VERSION_NUM,
.apiVersion = VK_API_VERSION_1_0,
.apiVersion = VK_API_VERSION_1_1,
};
VkInstanceCreateInfo instance_info = {
@ -278,10 +282,20 @@ VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd)
for (uint32_t i = 0; i < num_phdevs; ++i) {
VkPhysicalDevice phdev = phdevs[i];
// check whether device supports vulkan 1.1, needed for
// vkGetPhysicalDeviceProperties2
VkPhysicalDeviceProperties phdev_props;
vkGetPhysicalDeviceProperties(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
uint32_t avail_extc = 0;
res = vkEnumerateDeviceExtensionProperties(phdev, NULL,
@ -460,12 +474,6 @@ 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_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_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++) {
if (!check_extension(avail_ext_props, avail_extc, extensions[i])) {
@ -622,10 +630,6 @@ struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
load_device_proc(dev, "vkGetSemaphoreCounterValueKHR",
&dev->api.vkGetSemaphoreCounterValueKHR);
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) {
load_device_proc(dev, "vkGetSemaphoreFdKHR", &dev->api.vkGetSemaphoreFdKHR);

View file

@ -1,154 +0,0 @@
#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;
}

View file

@ -1,10 +0,0 @@
test(
'box',
executable('test-box', 'test_box.c', dependencies: wlroots),
)
benchmark(
'scene',
executable('bench-scene', 'bench_scene.c', dependencies: wlroots),
timeout: 30,
)

View file

@ -1,149 +0,0 @@
#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;
}

View file

@ -1,6 +1,6 @@
PKG_CONFIG?=pkg-config
PKGS="wlroots-0.21" wayland-server xkbcommon
PKGS="wlroots-0.20" wayland-server xkbcommon
CFLAGS_PKG_CONFIG!=$(PKG_CONFIG) --cflags $(PKGS)
CFLAGS+=$(CFLAGS_PKG_CONFIG)
LIBS!=$(PKG_CONFIG) --libs $(PKGS)

View file

@ -34,14 +34,13 @@ struct scene_node_source_frame_event {
static size_t last_output_num = 0;
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) {
static void _get_scene_node_extents(struct wlr_scene_node *node, struct wlr_box *box, int lx, int ly) {
switch (node->type) {
case WLR_SCENE_NODE_TREE:;
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
struct wlr_scene_node *child;
wl_list_for_each(child, &scene_tree->children, link) {
_get_scene_node_extents(child, lx + child->x, ly + child->y, x_min, y_min, x_max, y_max);
_get_scene_node_extents(child, box, lx + child->x, ly + child->y);
}
break;
case WLR_SCENE_NODE_RECT:
@ -49,30 +48,27 @@ static void _get_scene_node_extents(struct wlr_scene_node *node, int lx, int ly,
struct wlr_box node_box = { .x = lx, .y = ly };
scene_node_get_size(node, &node_box.width, &node_box.height);
if (node_box.x < *x_min) {
*x_min = node_box.x;
if (node_box.x < box->x) {
box->x = node_box.x;
}
if (node_box.y < *y_min) {
*y_min = node_box.y;
if (node_box.y < box->y) {
box->y = node_box.y;
}
if (node_box.x + node_box.width > *x_max) {
*x_max = node_box.x + node_box.width;
if (node_box.x + node_box.width > box->x + box->width) {
box->width = node_box.x + node_box.width - box->x;
}
if (node_box.y + node_box.height > *y_max) {
*y_max = node_box.y + node_box.height;
if (node_box.y + node_box.height > box->y + box->height) {
box->height = node_box.y + node_box.height - box->y;
}
break;
}
}
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;
wlr_scene_node_coords(node, &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;
_get_scene_node_extents(node, box, lx, ly);
}
static void source_render(struct scene_node_source *source) {

View file

@ -159,8 +159,9 @@ static void output_cursor_update_visible(struct wlr_output_cursor *cursor) {
struct wlr_box cursor_box;
output_cursor_get_box(cursor, &cursor_box);
struct wlr_box intersection;
cursor->visible =
wlr_box_intersects(&output_box, &cursor_box);
wlr_box_intersection(&intersection, &output_box, &cursor_box);
}
static bool output_pick_cursor_format(struct wlr_output *output,

View file

@ -233,11 +233,6 @@ static void output_apply_state(struct wlr_output *output,
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->image_description != NULL) {
output->image_description_value = *state->image_description;
@ -585,11 +580,6 @@ static uint32_t output_compare_state(struct wlr_output *output,
output->color_transform == 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;
}
@ -625,7 +615,7 @@ static bool output_basic_test(struct wlr_output *output,
};
struct wlr_box dst_box;
output_state_get_buffer_dst_box(state, &dst_box);
if (!wlr_box_intersects(&output_box, &dst_box)) {
if (!wlr_box_intersection(&output_box, &output_box, &dst_box)) {
wlr_log(WLR_ERROR, "Primary buffer is entirely off-screen or 0-sized");
return false;
}
@ -642,10 +632,6 @@ static bool output_basic_test(struct wlr_output *output,
wlr_log(WLR_DEBUG, "Tried to set signal timeline without a buffer");
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) {

View file

@ -141,14 +141,6 @@ bool wlr_output_state_set_image_description(struct wlr_output_state *state,
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,
const struct wlr_output_state *src) {
struct wlr_output_state copy = *src;

View file

@ -113,11 +113,24 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) {
if (node->type == WLR_SCENE_NODE_BUFFER) {
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_texture(scene_buffer, NULL);
pixman_region32_fini(&scene_buffer->opaque_region);
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.output_sample.listener_list));
assert(wl_list_empty(&scene_buffer->events.frame_done.listener_list));
@ -225,7 +238,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 };
scene_node_get_size(node, &node_box.width, &node_box.height);
if (wlr_box_intersects(&node_box, box) &&
if (wlr_box_intersection(&node_box, &node_box, box) &&
iterator(node, lx, ly, user_data)) {
return true;
}
@ -468,12 +481,28 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
(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
// output
assert(!active_outputs || scene_buffer->primary_output);
assert(!scene_buffer->active_outputs || scene_buffer->primary_output);
// Skip output update event if nothing was updated
if (scene_buffer->active_outputs == active_outputs &&
if (old_active == active_outputs &&
(!force || ((1ull << force->index) & ~active_outputs)) &&
old_primary_output == scene_buffer->primary_output) {
return;
@ -486,7 +515,6 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
};
size_t i = 0;
struct wlr_scene_output *scene_output;
wl_list_for_each(scene_output, outputs, link) {
if (~active_outputs & (1ull << scene_output->index)) {
continue;
@ -496,7 +524,6 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
outputs_array[i++] = scene_output;
}
scene_buffer->active_outputs = active_outputs;
wl_signal_emit_mutable(&scene_buffer->events.outputs_update, &event);
}
@ -842,6 +869,8 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *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.output_enter);
wl_signal_init(&scene_buffer->events.output_leave);
wl_signal_init(&scene_buffer->events.output_sample);
wl_signal_init(&scene_buffer->events.frame_done);
@ -2069,6 +2098,15 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout(
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
// 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.
@ -2116,17 +2154,6 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout(
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)) {
wlr_output_state_finish(&pending);
return SCANOUT_CANDIDATE;
@ -2669,7 +2696,8 @@ static void scene_output_for_each_scene_buffer(const struct wlr_box *output_box,
struct wlr_box node_box = { .x = lx, .y = ly };
scene_node_get_size(node, &node_box.width, &node_box.height);
if (wlr_box_intersects(output_box, &node_box)) {
struct wlr_box intersection;
if (wlr_box_intersection(&intersection, output_box, &node_box)) {
struct wlr_scene_buffer *scene_buffer =
wlr_scene_buffer_from_node(node);
user_iterator(scene_buffer, lx, ly, user_data);

View file

@ -260,12 +260,14 @@ bool wlr_output_layout_contains_point(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_box out_box;
if (reference == NULL) {
struct wlr_output_layout_output *l_output;
wl_list_for_each(l_output, &layout->outputs, link) {
struct wlr_box output_box;
output_layout_output_get_box(l_output, &output_box);
if (wlr_box_intersects(&output_box, target_lbox)) {
if (wlr_box_intersection(&out_box, &output_box, target_lbox)) {
return true;
}
}
@ -279,7 +281,7 @@ bool wlr_output_layout_intersects(struct wlr_output_layout *layout,
struct wlr_box output_box;
output_layout_output_get_box(l_output, &output_box);
return wlr_box_intersects(&output_box, target_lbox);
return wlr_box_intersection(&out_box, &output_box, target_lbox);
}
}

View file

@ -102,15 +102,6 @@ bool wlr_box_contains_box(const struct wlr_box *bigger, const struct wlr_box *sm
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,
enum wl_output_transform transform, int width, int height) {
struct wlr_box src = {0};

View file

@ -249,7 +249,7 @@ struct x11_data_source {
static const struct wlr_data_source_impl data_source_impl;
bool data_source_is_xwayland(
const struct wlr_data_source *wlr_source) {
struct wlr_data_source *wlr_source) {
return wlr_source->impl == &data_source_impl;
}
@ -292,7 +292,7 @@ static const struct wlr_primary_selection_source_impl
primary_selection_source_impl;
bool primary_selection_source_is_xwayland(
const struct wlr_primary_selection_source *wlr_source) {
struct wlr_primary_selection_source *wlr_source) {
return wlr_source->impl == &primary_selection_source_impl;
}