Compare commits

...

30 commits

Author SHA1 Message Date
Kenny Levinsen
1ce992d7cb scene/layer_shell_v1: Add support for exclusive_edge
The v5 layer shell interface allows the client to specify which edge the
exclusive zone will apply to, instead of deducing it from the anchor
points. Add support for this to the layer shell scene helper.
2026-02-24 13:28:46 +00:00
Simon Ser
2367d78c3c render/vulkan: fix missing DMA-BUF implicit write fence for render buffer
Same as previous commit for the read side, but this one waits for
all readers to be done before starting to write.
2026-02-23 09:33:27 -05:00
Simon Ser
8c8d6363a1 render/vulkan: add "acquire" to vulkan_sync_foreign_texture()
Makes it more obvious that this is about the acquire side, not the
release side.
2026-02-23 09:33:27 -05:00
Simon Ser
ff4ce12179 render/vulkan: introduce buffer_export_sync_file()
Same as buffer_import_sync_file(), but for the export side.
2026-02-23 09:33:27 -05:00
Simon Ser
43b37e34d6 render/vulkan: fix missing DMA-BUF implicit read fence for textures
When we're reading from a DMA-BUF texture using implicit sync, we
need to (1) wait for any writer to be done and (2) prevent any
writers from mutating the texture while we're still reading. We
were doing (1) but not (2).

Fix this by calling dmabuf_import_sync_file() with DMA_BUF_SYNC_READ
for all DMA-BUF textures we've used in the render pass.
2026-02-23 09:33:27 -05:00
Simon Ser
73bbad8433 render/vulkan: take render pass in vulkan_sync_render_buffer()
We'll need to grab textures from there in the next commit.

Also rename it to better reflect what it does: synchronize release
fences after a render pass has been submitted.
2026-02-23 09:33:27 -05:00
Simon Ser
a6e5807e86 render/vulkan: introduce buffer_import_sync_file()
Will be used in two spots in a following commit.
2026-02-23 09:33:27 -05:00
Simon Ser
7be5e3689c build: bump version to 0.20.0-rc3 2026-02-22 23:38:52 +01:00
hrdl
25bec59c75 CONTRIBUTING.md: update git host
gitlab.freedesktop.org -> ssh.gitlab.freedesktop.org
2026-02-20 00:31:06 +01:00
Kenny Levinsen
1efb216c6d backend/drm: Close non-master drm fd on failure
If we are not able to prepare the fd for non-master usage, close the fd
before returning an error.
2026-02-19 15:11:56 +00:00
Simon Ser
884d29e5f3 backend/libinput: guard against new enum entries
When libinput introduces new enum entries, we'd abort or send bogus
events to the compositor. Instead, log a message and ignore the
event.

Keep all enums without a default case so that the compiler warns
when we're missing a case.
2026-02-13 09:41:02 -05:00
Isaac Freund
25f94c5965
backend/x11: reject shm buffers with non-min strides
This fixes an X11 backend direct scanout bug with foot.

Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/4046
2026-02-13 11:56:08 +01:00
Simon Ser
910fd264fb build: bump version to 0.20.0-rc2 2026-02-12 22:47:22 +01:00
Aleksei Bavshin
3676ab4df0
backend/libinput: add support for LIBINPUT_SWITCH_KEYPAD_SLIDE 2026-02-08 11:01:06 -08:00
Aleksei Bavshin
c1452d8811
backend/libinput: fix build with libinput 1.31 2026-02-08 10:56:16 -08:00
Steve Williams
436bcf9a47 color-representation-v1: fix condition in surface commit 2026-02-07 08:36:29 +04:00
Steve Williams
ef88246642 types/wlr_buffer: add buffer_get_drm_format helper function 2026-02-06 13:53:46 +00:00
Steve Williams
bb78861ca9 color-representation: add support for identity+full 2026-02-06 13:53:46 +00:00
Steve Williams
439985fe95 color_representation: ensure encoding/range/drm formats compatibility 2026-02-06 13:53:46 +00:00
Steve Williams
4c81cb1b9e vulkan: make use of new pixel_format_is_ycbcr function 2026-02-06 13:53:46 +00:00
Steve Williams
19d6829601 render/pixel-format: add function to determine YCbCr from drm fourcc 2026-02-06 13:53:46 +00:00
YaoBing Xiao
dfccf5ff02 output/cursor: fix missing newline at end of file 2026-02-06 09:05:52 +00:00
rewine
bc11ac92ab
ext_image_capture_source_v1: remove unused variable 2026-02-06 10:41:42 +08:00
YaoBing Xiao
d362ed1eb9 xwayland: fix wl_array rollback when adding selection targets
Ensure mime_types and mime_types_atoms remain in sync when
wl_array_add() fails. Roll back the partially added entry and
free the allocated mime type to avoid leaks and inconsistent
state.
2026-02-05 09:26:55 +08:00
Simon Ser
90f9f59041 xwayland: try flushing immediately in xwm_schedule_flush()
wl_event_source_fd_update() goes through another event loop cycle, which
delays writes. This extra cycle was introduced in 6ada67da9b
("xwayland/xwm: implement somewhat asynchronous request flushing").

Try flushing the X11 WM FD immediately if we can.

References: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/4044
2026-02-04 00:14:49 +01:00
rewine
7cb4e30bfd
wlr_cursor: fix event type in handle_tablet_tool_button 2026-02-03 21:25:50 +08:00
rewine
98196bbd89
wlr_cursor: add comments for signal parameters 2026-02-03 21:24:32 +08:00
rewine
4fe51aa439 types: Simplify wlr_keyboard_group_destroy
If the wlr_keyboard_group_remove_keyboard function is expanded, the code
is equivalent to:

```
	wl_list_for_each_safe(device, tmp_device, &group->devices, link) {
		struct wlr_keyboard_group *_group = group;
		struct wlr_keyboard *_keyboard = device->keyboard;
		struct keyboard_group_device *_device, *_tmp;
		wl_list_for_each_safe(_device, _tmp, &_group->devices, link) {
			if (_device->keyboard == _keyboard) {
				remove_keyboard_group_device(_device);
				continue;
			}
		}
	}
```

It's just running one more loop meaninglessly.
2026-02-02 10:46:20 -05:00
liupeng
12c9502edf render/drm_syncobj: fix function name in drmSyncobjTimelineWait() error log
Signed-off-by: liupeng <liupeng01@kylinos.cn>
2026-02-02 09:12:39 +08:00
liupeng
7f87e258b2 render/drm_syncobj: drop unnecessary drmSyncobjTimelineWait() arg
Signed-off-by: liupeng <liupeng01@kylinos.cn>
2026-02-02 09:11:41 +08:00
33 changed files with 518 additions and 213 deletions

View file

@ -22,7 +22,7 @@ don't, however, allow me to make a suggestion: feature branches pulled from
upstream. Try this: upstream. Try this:
1. Fork wlroots 1. Fork wlroots
2. `git clone git@gitlab.freedesktop.org:<username>/wlroots.git && cd wlroots` 2. `git clone git@ssh.gitlab.freedesktop.org:<username>/wlroots.git && cd wlroots`
3. `git remote add upstream https://gitlab.freedesktop.org/wlroots/wlroots.git` 3. `git remote add upstream https://gitlab.freedesktop.org/wlroots/wlroots.git`
You only need to do this once. You're never going to use your fork's master You only need to do this once. You're never going to use your fork's master

View file

@ -2104,6 +2104,7 @@ int wlr_drm_backend_get_non_master_fd(struct wlr_backend *backend) {
if (drmIsMaster(fd) && drmDropMaster(fd) < 0) { if (drmIsMaster(fd) && drmDropMaster(fd) < 0) {
wlr_log_errno(WLR_ERROR, "Failed to drop master"); wlr_log_errno(WLR_ERROR, "Failed to drop master");
close(fd);
return -1; return -1;
} }

View file

@ -249,3 +249,15 @@ void handle_libinput_event(struct wlr_libinput_backend *backend,
break; break;
} }
} }
bool button_state_from_libinput(enum libinput_button_state state, enum wlr_button_state *out) {
switch (state) {
case LIBINPUT_BUTTON_STATE_RELEASED:
*out = WLR_BUTTON_RELEASED;
return true;
case LIBINPUT_BUTTON_STATE_PRESSED:
*out = WLR_BUTTON_PRESSED;
return true;
}
return false;
}

View file

@ -2,6 +2,7 @@
#include <libinput.h> #include <libinput.h>
#include <stdlib.h> #include <stdlib.h>
#include <wlr/interfaces/wlr_keyboard.h> #include <wlr/interfaces/wlr_keyboard.h>
#include <wlr/util/log.h>
#include "backend/libinput.h" #include "backend/libinput.h"
struct wlr_libinput_input_device *device_from_keyboard( struct wlr_libinput_input_device *device_from_keyboard(
@ -30,6 +31,18 @@ void init_device_keyboard(struct wlr_libinput_input_device *dev) {
libinput_device_led_update(dev->handle, 0); libinput_device_led_update(dev->handle, 0);
} }
static bool key_state_from_libinput(enum libinput_key_state state, enum wl_keyboard_key_state *out) {
switch (state) {
case LIBINPUT_KEY_STATE_RELEASED:
*out = WL_KEYBOARD_KEY_STATE_RELEASED;
return true;
case LIBINPUT_KEY_STATE_PRESSED:
*out = WL_KEYBOARD_KEY_STATE_PRESSED;
return true;
}
return false;
}
void handle_keyboard_key(struct libinput_event *event, void handle_keyboard_key(struct libinput_event *event,
struct wlr_keyboard *kb) { struct wlr_keyboard *kb) {
struct libinput_event_keyboard *kbevent = struct libinput_event_keyboard *kbevent =
@ -39,13 +52,9 @@ void handle_keyboard_key(struct libinput_event *event,
.keycode = libinput_event_keyboard_get_key(kbevent), .keycode = libinput_event_keyboard_get_key(kbevent),
.update_state = true, .update_state = true,
}; };
switch (libinput_event_keyboard_get_key_state(kbevent)) { if (!key_state_from_libinput(libinput_event_keyboard_get_key_state(kbevent), &wlr_event.state)) {
case LIBINPUT_KEY_STATE_RELEASED: wlr_log(WLR_DEBUG, "Unhandled libinput key state");
wlr_event.state = WL_KEYBOARD_KEY_STATE_RELEASED; return;
break;
case LIBINPUT_KEY_STATE_PRESSED:
wlr_event.state = WL_KEYBOARD_KEY_STATE_PRESSED;
break;
} }
wlr_keyboard_notify_key(kb, &wlr_event); wlr_keyboard_notify_key(kb, &wlr_event);
} }

View file

@ -29,3 +29,7 @@ features += { 'libinput-backend': true }
wlr_deps += libinput wlr_deps += libinput
internal_config.set10('HAVE_LIBINPUT_BUSTYPE', libinput.version().version_compare('>=1.26.0')) internal_config.set10('HAVE_LIBINPUT_BUSTYPE', libinput.version().version_compare('>=1.26.0'))
internal_config.set10(
'HAVE_LIBINPUT_SWITCH_KEYPAD_SLIDE',
libinput.version().version_compare('>=1.30.901')
)

View file

@ -1,6 +1,7 @@
#include <assert.h> #include <assert.h>
#include <libinput.h> #include <libinput.h>
#include <wlr/interfaces/wlr_pointer.h> #include <wlr/interfaces/wlr_pointer.h>
#include <wlr/util/log.h>
#include "backend/libinput.h" #include "backend/libinput.h"
const struct wlr_pointer_impl libinput_pointer_impl = { const struct wlr_pointer_impl libinput_pointer_impl = {
@ -52,6 +53,38 @@ void handle_pointer_motion_abs(struct libinput_event *event,
wl_signal_emit_mutable(&pointer->events.frame, pointer); wl_signal_emit_mutable(&pointer->events.frame, pointer);
} }
static bool pointer_button_state_from_libinput(enum libinput_button_state state,
enum wl_pointer_button_state *out) {
switch (state) {
case LIBINPUT_BUTTON_STATE_PRESSED:
*out = WL_POINTER_BUTTON_STATE_PRESSED;
return true;
case LIBINPUT_BUTTON_STATE_RELEASED:
*out = WL_POINTER_BUTTON_STATE_RELEASED;
return true;
}
return false;
}
static bool axis_source_from_libinput(enum libinput_pointer_axis_source source,
enum wl_pointer_axis_source *out) {
switch (source) {
case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
*out = WL_POINTER_AXIS_SOURCE_WHEEL;
return true;
case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
*out = WL_POINTER_AXIS_SOURCE_FINGER;
return true;
case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
*out = WL_POINTER_AXIS_SOURCE_CONTINUOUS;
return true;
case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT:
*out = WL_POINTER_AXIS_SOURCE_WHEEL_TILT;
return true;
}
return false;
}
void handle_pointer_button(struct libinput_event *event, void handle_pointer_button(struct libinput_event *event,
struct wlr_pointer *pointer) { struct wlr_pointer *pointer) {
struct libinput_event_pointer *pevent = struct libinput_event_pointer *pevent =
@ -61,13 +94,10 @@ void handle_pointer_button(struct libinput_event *event,
.time_msec = usec_to_msec(libinput_event_pointer_get_time_usec(pevent)), .time_msec = usec_to_msec(libinput_event_pointer_get_time_usec(pevent)),
.button = libinput_event_pointer_get_button(pevent), .button = libinput_event_pointer_get_button(pevent),
}; };
switch (libinput_event_pointer_get_button_state(pevent)) { if (!pointer_button_state_from_libinput(libinput_event_pointer_get_button_state(pevent),
case LIBINPUT_BUTTON_STATE_PRESSED: &wlr_event.state)) {
wlr_event.state = WL_POINTER_BUTTON_STATE_PRESSED; wlr_log(WLR_DEBUG, "Unhandled libinput button state");
break; return;
case LIBINPUT_BUTTON_STATE_RELEASED:
wlr_event.state = WL_POINTER_BUTTON_STATE_RELEASED;
break;
} }
wlr_pointer_notify_button(pointer, &wlr_event); wlr_pointer_notify_button(pointer, &wlr_event);
wl_signal_emit_mutable(&pointer->events.frame, pointer); wl_signal_emit_mutable(&pointer->events.frame, pointer);
@ -81,19 +111,9 @@ void handle_pointer_axis(struct libinput_event *event,
.pointer = pointer, .pointer = pointer,
.time_msec = usec_to_msec(libinput_event_pointer_get_time_usec(pevent)), .time_msec = usec_to_msec(libinput_event_pointer_get_time_usec(pevent)),
}; };
switch (libinput_event_pointer_get_axis_source(pevent)) { if (!axis_source_from_libinput(libinput_event_pointer_get_axis_source(pevent), &wlr_event.source)) {
case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL: wlr_log(WLR_DEBUG, "Unhandled libinput pointer axis source");
wlr_event.source = WL_POINTER_AXIS_SOURCE_WHEEL; return;
break;
case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
wlr_event.source = WL_POINTER_AXIS_SOURCE_FINGER;
break;
case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
wlr_event.source = WL_POINTER_AXIS_SOURCE_CONTINUOUS;
break;
case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT:
wlr_event.source = WL_POINTER_AXIS_SOURCE_WHEEL_TILT;
break;
} }
const enum libinput_pointer_axis axes[] = { const enum libinput_pointer_axis axes[] = {
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,

View file

@ -1,7 +1,9 @@
#include <assert.h> #include <assert.h>
#include <libinput.h> #include <libinput.h>
#include <wlr/interfaces/wlr_switch.h> #include <wlr/interfaces/wlr_switch.h>
#include <wlr/util/log.h>
#include "backend/libinput.h" #include "backend/libinput.h"
#include "config.h"
const struct wlr_switch_impl libinput_switch_impl = { const struct wlr_switch_impl libinput_switch_impl = {
.name = "libinput-switch", .name = "libinput-switch",
@ -22,6 +24,35 @@ struct wlr_libinput_input_device *device_from_switch(
return dev; return dev;
} }
static bool switch_type_from_libinput(enum libinput_switch type, enum wlr_switch_type *out) {
switch (type) {
case LIBINPUT_SWITCH_LID:
*out = WLR_SWITCH_TYPE_LID;
return true;
case LIBINPUT_SWITCH_TABLET_MODE:
*out = WLR_SWITCH_TYPE_TABLET_MODE;
return true;
#if HAVE_LIBINPUT_SWITCH_KEYPAD_SLIDE
case LIBINPUT_SWITCH_KEYPAD_SLIDE:
*out = WLR_SWITCH_TYPE_KEYPAD_SLIDE;
return true;
#endif
}
return false;
}
static bool switch_state_from_libinput(enum libinput_switch_state state, enum wlr_switch_state *out) {
switch (state) {
case LIBINPUT_SWITCH_STATE_OFF:
*out = WLR_SWITCH_STATE_OFF;
return true;
case LIBINPUT_SWITCH_STATE_ON:
*out = WLR_SWITCH_STATE_ON;
return true;
}
return false;
}
void handle_switch_toggle(struct libinput_event *event, void handle_switch_toggle(struct libinput_event *event,
struct wlr_switch *wlr_switch) { struct wlr_switch *wlr_switch) {
struct libinput_event_switch *sevent = struct libinput_event_switch *sevent =
@ -29,21 +60,13 @@ void handle_switch_toggle(struct libinput_event *event,
struct wlr_switch_toggle_event wlr_event = { struct wlr_switch_toggle_event wlr_event = {
.time_msec = usec_to_msec(libinput_event_switch_get_time_usec(sevent)), .time_msec = usec_to_msec(libinput_event_switch_get_time_usec(sevent)),
}; };
switch (libinput_event_switch_get_switch(sevent)) { if (!switch_type_from_libinput(libinput_event_switch_get_switch(sevent), &wlr_event.switch_type)) {
case LIBINPUT_SWITCH_LID: wlr_log(WLR_DEBUG, "Unhandled libinput switch type");
wlr_event.switch_type = WLR_SWITCH_TYPE_LID; return;
break;
case LIBINPUT_SWITCH_TABLET_MODE:
wlr_event.switch_type = WLR_SWITCH_TYPE_TABLET_MODE;
break;
} }
switch (libinput_event_switch_get_switch_state(sevent)) { if (!switch_state_from_libinput(libinput_event_switch_get_switch_state(sevent), &wlr_event.switch_state)) {
case LIBINPUT_SWITCH_STATE_OFF: wlr_log(WLR_DEBUG, "Unhandled libinput switch state");
wlr_event.switch_state = WLR_SWITCH_STATE_OFF; return;
break;
case LIBINPUT_SWITCH_STATE_ON:
wlr_event.switch_state = WLR_SWITCH_STATE_ON;
break;
} }
wl_signal_emit_mutable(&wlr_switch->events.toggle, &wlr_event); wl_signal_emit_mutable(&wlr_switch->events.toggle, &wlr_event);
} }

View file

@ -148,13 +148,9 @@ void handle_tablet_pad_button(struct libinput_event *event,
.group = libinput_tablet_pad_mode_group_get_index( .group = libinput_tablet_pad_mode_group_get_index(
libinput_event_tablet_pad_get_mode_group(pevent)), libinput_event_tablet_pad_get_mode_group(pevent)),
}; };
switch (libinput_event_tablet_pad_get_button_state(pevent)) { if (!button_state_from_libinput(libinput_event_tablet_pad_get_button_state(pevent), &wlr_event.state)) {
case LIBINPUT_BUTTON_STATE_PRESSED: wlr_log(WLR_DEBUG, "Unhandled libinput button state");
wlr_event.state = WLR_BUTTON_PRESSED; return;
break;
case LIBINPUT_BUTTON_STATE_RELEASED:
wlr_event.state = WLR_BUTTON_RELEASED;
break;
} }
wl_signal_emit_mutable(&tablet_pad->events.button, &wlr_event); wl_signal_emit_mutable(&tablet_pad->events.button, &wlr_event);
} }
@ -168,6 +164,7 @@ void handle_tablet_pad_ring(struct libinput_event *event,
.ring = libinput_event_tablet_pad_get_ring_number(pevent), .ring = libinput_event_tablet_pad_get_ring_number(pevent),
.position = libinput_event_tablet_pad_get_ring_position(pevent), .position = libinput_event_tablet_pad_get_ring_position(pevent),
.mode = libinput_event_tablet_pad_get_mode(pevent), .mode = libinput_event_tablet_pad_get_mode(pevent),
.source = WLR_TABLET_PAD_RING_SOURCE_UNKNOWN,
}; };
switch (libinput_event_tablet_pad_get_ring_source(pevent)) { switch (libinput_event_tablet_pad_get_ring_source(pevent)) {
case LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN: case LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN:
@ -189,6 +186,7 @@ void handle_tablet_pad_strip(struct libinput_event *event,
.strip = libinput_event_tablet_pad_get_strip_number(pevent), .strip = libinput_event_tablet_pad_get_strip_number(pevent),
.position = libinput_event_tablet_pad_get_strip_position(pevent), .position = libinput_event_tablet_pad_get_strip_position(pevent),
.mode = libinput_event_tablet_pad_get_mode(pevent), .mode = libinput_event_tablet_pad_get_mode(pevent),
.source = WLR_TABLET_PAD_STRIP_SOURCE_UNKNOWN,
}; };
switch (libinput_event_tablet_pad_get_strip_source(pevent)) { switch (libinput_event_tablet_pad_get_strip_source(pevent)) {
case LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN: case LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN:

View file

@ -78,27 +78,61 @@ struct wlr_libinput_input_device *device_from_tablet(
return dev; return dev;
} }
static enum wlr_tablet_tool_type wlr_type_from_libinput_type( static bool type_from_libinput(enum libinput_tablet_tool_type type,
enum libinput_tablet_tool_type value) { enum wlr_tablet_tool_type *out) {
switch (value) { switch (type) {
case LIBINPUT_TABLET_TOOL_TYPE_PEN: case LIBINPUT_TABLET_TOOL_TYPE_PEN:
return WLR_TABLET_TOOL_TYPE_PEN; *out = WLR_TABLET_TOOL_TYPE_PEN;
return true;
case LIBINPUT_TABLET_TOOL_TYPE_ERASER: case LIBINPUT_TABLET_TOOL_TYPE_ERASER:
return WLR_TABLET_TOOL_TYPE_ERASER; *out = WLR_TABLET_TOOL_TYPE_ERASER;
return true;
case LIBINPUT_TABLET_TOOL_TYPE_BRUSH: case LIBINPUT_TABLET_TOOL_TYPE_BRUSH:
return WLR_TABLET_TOOL_TYPE_BRUSH; *out = WLR_TABLET_TOOL_TYPE_BRUSH;
return true;
case LIBINPUT_TABLET_TOOL_TYPE_PENCIL: case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:
return WLR_TABLET_TOOL_TYPE_PENCIL; *out = WLR_TABLET_TOOL_TYPE_PENCIL;
return true;
case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH: case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:
return WLR_TABLET_TOOL_TYPE_AIRBRUSH; *out = WLR_TABLET_TOOL_TYPE_AIRBRUSH;
return true;
case LIBINPUT_TABLET_TOOL_TYPE_MOUSE: case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:
return WLR_TABLET_TOOL_TYPE_MOUSE; *out = WLR_TABLET_TOOL_TYPE_MOUSE;
return true;
case LIBINPUT_TABLET_TOOL_TYPE_LENS: case LIBINPUT_TABLET_TOOL_TYPE_LENS:
return WLR_TABLET_TOOL_TYPE_LENS; *out = WLR_TABLET_TOOL_TYPE_LENS;
return true;
case LIBINPUT_TABLET_TOOL_TYPE_TOTEM: case LIBINPUT_TABLET_TOOL_TYPE_TOTEM:
return WLR_TABLET_TOOL_TYPE_TOTEM; *out = WLR_TABLET_TOOL_TYPE_TOTEM;
return true;
} }
abort(); // unreachable return false;
}
static bool proximity_state_from_libinput(enum libinput_tablet_tool_proximity_state state,
enum wlr_tablet_tool_proximity_state *out) {
switch (state) {
case LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT:
*out = WLR_TABLET_TOOL_PROXIMITY_OUT;
return true;
case LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN:
*out = WLR_TABLET_TOOL_PROXIMITY_IN;
return true;
}
return false;
}
static bool tip_state_from_libinput(enum libinput_tablet_tool_tip_state state,
enum wlr_tablet_tool_tip_state *out) {
switch (state) {
case LIBINPUT_TABLET_TOOL_TIP_UP:
*out = WLR_TABLET_TOOL_TIP_UP;
return true;
case LIBINPUT_TABLET_TOOL_TIP_DOWN:
*out = WLR_TABLET_TOOL_TIP_DOWN;
return true;
}
return false;
} }
static struct tablet_tool *get_tablet_tool( static struct tablet_tool *get_tablet_tool(
@ -110,14 +144,19 @@ static struct tablet_tool *get_tablet_tool(
return tool; return tool;
} }
enum wlr_tablet_tool_type type;
if (!type_from_libinput(libinput_tablet_tool_get_type(libinput_tool), &type)) {
wlr_log(WLR_DEBUG, "Unhandled libinput tablet tool type");
return NULL;
}
tool = calloc(1, sizeof(*tool)); tool = calloc(1, sizeof(*tool));
if (tool == NULL) { if (tool == NULL) {
wlr_log_errno(WLR_ERROR, "failed to allocate wlr_libinput_tablet_tool"); wlr_log_errno(WLR_ERROR, "failed to allocate wlr_libinput_tablet_tool");
return NULL; return NULL;
} }
tool->wlr_tool.type = wlr_type_from_libinput_type( tool->wlr_tool.type = type;
libinput_tablet_tool_get_type(libinput_tool));
tool->wlr_tool.hardware_serial = tool->wlr_tool.hardware_serial =
libinput_tablet_tool_get_serial(libinput_tool); libinput_tablet_tool_get_serial(libinput_tool);
tool->wlr_tool.hardware_wacom = tool->wlr_tool.hardware_wacom =
@ -209,14 +248,12 @@ void handle_tablet_tool_proximity(struct libinput_event *event,
.y = libinput_event_tablet_tool_get_y_transformed(tevent, 1), .y = libinput_event_tablet_tool_get_y_transformed(tevent, 1),
}; };
switch (libinput_event_tablet_tool_get_proximity_state(tevent)) { if (!proximity_state_from_libinput(libinput_event_tablet_tool_get_proximity_state(tevent),
case LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT: &wlr_event.state)) {
wlr_event.state = WLR_TABLET_TOOL_PROXIMITY_OUT; wlr_log(WLR_DEBUG, "Unhandled libinput tablet tool proximity state");
break; return;
case LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN:
wlr_event.state = WLR_TABLET_TOOL_PROXIMITY_IN;
break;
} }
wl_signal_emit_mutable(&wlr_tablet->events.proximity, &wlr_event); wl_signal_emit_mutable(&wlr_tablet->events.proximity, &wlr_event);
if (libinput_event_tablet_tool_get_proximity_state(tevent) == if (libinput_event_tablet_tool_get_proximity_state(tevent) ==
@ -251,14 +288,11 @@ void handle_tablet_tool_tip(struct libinput_event *event,
.y = libinput_event_tablet_tool_get_y_transformed(tevent, 1), .y = libinput_event_tablet_tool_get_y_transformed(tevent, 1),
}; };
switch (libinput_event_tablet_tool_get_tip_state(tevent)) { if (!tip_state_from_libinput(libinput_event_tablet_tool_get_tip_state(tevent), &wlr_event.state)) {
case LIBINPUT_TABLET_TOOL_TIP_UP: wlr_log(WLR_DEBUG, "Unhandled libinput tablet tool tip state");
wlr_event.state = WLR_TABLET_TOOL_TIP_UP; return;
break;
case LIBINPUT_TABLET_TOOL_TIP_DOWN:
wlr_event.state = WLR_TABLET_TOOL_TIP_DOWN;
break;
} }
wl_signal_emit_mutable(&wlr_tablet->events.tip, &wlr_event); wl_signal_emit_mutable(&wlr_tablet->events.tip, &wlr_event);
} }
@ -277,13 +311,11 @@ void handle_tablet_tool_button(struct libinput_event *event,
.time_msec = usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)), .time_msec = usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)),
.button = libinput_event_tablet_tool_get_button(tevent), .button = libinput_event_tablet_tool_get_button(tevent),
}; };
switch (libinput_event_tablet_tool_get_button_state(tevent)) {
case LIBINPUT_BUTTON_STATE_RELEASED: if (!button_state_from_libinput(libinput_event_tablet_tool_get_button_state(tevent), &wlr_event.state)) {
wlr_event.state = WLR_BUTTON_RELEASED; wlr_log(WLR_DEBUG, "Unhandled libinput button state");
break; return;
case LIBINPUT_BUTTON_STATE_PRESSED:
wlr_event.state = WLR_BUTTON_PRESSED;
break;
} }
wl_signal_emit_mutable(&wlr_tablet->events.button, &wlr_event); wl_signal_emit_mutable(&wlr_tablet->events.button, &wlr_event);
} }

View file

@ -19,7 +19,9 @@
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "backend/x11.h" #include "backend/x11.h"
#include "render/pixel_format.h"
#include "util/time.h" #include "util/time.h"
#include "types/wlr_buffer.h"
#include "types/wlr_output.h" #include "types/wlr_output.h"
static const uint32_t SUPPORTED_OUTPUT_STATE = static const uint32_t SUPPORTED_OUTPUT_STATE =
@ -166,18 +168,20 @@ static bool output_test(struct wlr_output *wlr_output,
if (state->committed & WLR_OUTPUT_STATE_BUFFER) { if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
struct wlr_buffer *buffer = state->buffer; struct wlr_buffer *buffer = state->buffer;
struct wlr_dmabuf_attributes dmabuf_attrs; uint32_t format = buffer_get_drm_format(buffer);
struct wlr_shm_attributes shm_attrs;
uint32_t format = DRM_FORMAT_INVALID;
if (wlr_buffer_get_dmabuf(buffer, &dmabuf_attrs)) {
format = dmabuf_attrs.format;
} else if (wlr_buffer_get_shm(buffer, &shm_attrs)) {
format = shm_attrs.format;
}
if (format != x11->x11_format->drm) { if (format != x11->x11_format->drm) {
wlr_log(WLR_DEBUG, "Unsupported buffer format"); wlr_log(WLR_DEBUG, "Unsupported buffer format");
return false; return false;
} }
struct wlr_shm_attributes shm;
if (wlr_buffer_get_shm(buffer, &shm)) {
const struct wlr_pixel_format_info *info = drm_get_pixel_format_info(format);
if (shm.stride != pixel_format_info_min_stride(info, shm.width)) {
// xcb_shm_create_pixmap() does not allow arbitrary strides.
wlr_log(WLR_DEBUG, "Unsupported shm buffer stride");
return false;
}
}
} }
if (state->committed & WLR_OUTPUT_STATE_MODE) { if (state->committed & WLR_OUTPUT_STATE_MODE) {
@ -267,6 +271,12 @@ static xcb_pixmap_t import_shm(struct wlr_x11_output *output,
return XCB_PIXMAP_NONE; return XCB_PIXMAP_NONE;
} }
const struct wlr_pixel_format_info *info = drm_get_pixel_format_info(shm->format);
if (shm->stride != pixel_format_info_min_stride(info, shm->width)) {
// xcb_shm_create_pixmap() does not allow arbitrary strides.
return XCB_PIXMAP_NONE;
}
// xcb closes the FD after sending it // xcb closes the FD after sending it
int fd = fcntl(shm->fd, F_DUPFD_CLOEXEC, 0); int fd = fcntl(shm->fd, F_DUPFD_CLOEXEC, 0);
if (fd < 0) { if (fd < 0) {

View file

@ -132,4 +132,6 @@ void handle_tablet_pad_ring(struct libinput_event *event,
void handle_tablet_pad_strip(struct libinput_event *event, void handle_tablet_pad_strip(struct libinput_event *event,
struct wlr_tablet_pad *tablet_pad); struct wlr_tablet_pad *tablet_pad);
bool button_state_from_libinput(enum libinput_button_state state, enum wlr_button_state *out);
#endif #endif

View file

@ -63,4 +63,9 @@ enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt);
*/ */
bool pixel_format_has_alpha(uint32_t fmt); bool pixel_format_has_alpha(uint32_t fmt);
/**
* Return true if the DRM FourCC fmt belongs to a YCbCr colorspace family, false otherwise.
*/
bool pixel_format_is_ycbcr(uint32_t fmt);
#endif #endif

View file

@ -86,7 +86,6 @@ struct wlr_vk_format {
uint32_t drm; uint32_t drm;
VkFormat vk; VkFormat vk;
VkFormat vk_srgb; // sRGB version of the format, or 0 if nonexistent VkFormat vk_srgb; // sRGB version of the format, or 0 if nonexistent
bool is_ycbcr;
}; };
extern const VkImageUsageFlags vulkan_render_usage, vulkan_shm_tex_usage, vulkan_dma_tex_usage; extern const VkImageUsageFlags vulkan_render_usage, vulkan_shm_tex_usage, vulkan_dma_tex_usage;
@ -125,6 +124,7 @@ void vulkan_format_props_query(struct wlr_vk_device *dev,
const struct wlr_vk_format_modifier_props *vulkan_format_props_find_modifier( const struct wlr_vk_format_modifier_props *vulkan_format_props_find_modifier(
const struct wlr_vk_format_props *props, uint64_t mod, bool render); const struct wlr_vk_format_props *props, uint64_t mod, bool render);
void vulkan_format_props_finish(struct wlr_vk_format_props *props); void vulkan_format_props_finish(struct wlr_vk_format_props *props);
bool vulkan_format_is_ycbcr(const struct wlr_vk_format *format);
struct wlr_vk_pipeline_layout_key { struct wlr_vk_pipeline_layout_key {
enum wlr_scale_filter_mode filter_mode; enum wlr_scale_filter_mode filter_mode;
@ -473,10 +473,11 @@ 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);
bool vulkan_sync_render_buffer(struct wlr_vk_renderer *renderer, bool vulkan_sync_render_pass_release(struct wlr_vk_renderer *renderer,
struct wlr_vk_render_buffer *render_buffer, struct wlr_vk_command_buffer *cb, struct wlr_vk_render_pass *pass);
struct wlr_drm_syncobj_timeline *signal_timeline, uint64_t signal_point); bool vulkan_sync_foreign_texture_acquire(struct wlr_vk_texture *texture,
bool vulkan_sync_foreign_texture(struct wlr_vk_texture *texture, int sync_file_fds[static WLR_DMABUF_MAX_PLANES]);
bool vulkan_sync_render_buffer_acquire(struct wlr_vk_render_buffer *render_buffer,
int sync_file_fds[static WLR_DMABUF_MAX_PLANES]); int sync_file_fds[static WLR_DMABUF_MAX_PLANES]);
bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer, bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,

View file

@ -65,4 +65,10 @@ struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer,
bool wlr_client_buffer_apply_damage(struct wlr_client_buffer *client_buffer, bool wlr_client_buffer_apply_damage(struct wlr_client_buffer *client_buffer,
struct wlr_buffer *next, const pixman_region32_t *damage); struct wlr_buffer *next, const pixman_region32_t *damage);
/**
* Return the DRM format of the buffer. If this buffer isn't shared
* memory or a DMA-BUF, returns DRM_FORMAT_INVALID.
*/
uint32_t buffer_get_drm_format(struct wlr_buffer *buffer);
#endif #endif

View file

@ -49,30 +49,30 @@ struct wlr_cursor {
* your responsibility. * your responsibility.
*/ */
struct { struct {
struct wl_signal motion; struct wl_signal motion; // struct wlr_pointer_motion_event
struct wl_signal motion_absolute; struct wl_signal motion_absolute; // struct wlr_pointer_motion_absolute_event
struct wl_signal button; struct wl_signal button; // struct wlr_pointer_button_event
struct wl_signal axis; struct wl_signal axis; // struct wlr_pointer_axis_event
struct wl_signal frame; struct wl_signal frame;
struct wl_signal swipe_begin; struct wl_signal swipe_begin; // struct wlr_pointer_swipe_begin_event
struct wl_signal swipe_update; struct wl_signal swipe_update; // struct wlr_pointer_swipe_update_event
struct wl_signal swipe_end; struct wl_signal swipe_end; // struct wlr_pointer_swipe_end_event
struct wl_signal pinch_begin; struct wl_signal pinch_begin; // struct wlr_pointer_pinch_begin_event
struct wl_signal pinch_update; struct wl_signal pinch_update; // struct wlr_pointer_pinch_update_event
struct wl_signal pinch_end; struct wl_signal pinch_end; // struct wlr_pointer_pinch_end_event
struct wl_signal hold_begin; struct wl_signal hold_begin; // struct wlr_pointer_hold_begin_event
struct wl_signal hold_end; struct wl_signal hold_end; // struct wlr_pointer_hold_end_event
struct wl_signal touch_up; struct wl_signal touch_up; // struct wlr_touch_up_event
struct wl_signal touch_down; struct wl_signal touch_down; // struct wlr_touch_down_event
struct wl_signal touch_motion; struct wl_signal touch_motion; // struct wlr_touch_motion_event
struct wl_signal touch_cancel; struct wl_signal touch_cancel; // struct wlr_touch_cancel_event
struct wl_signal touch_frame; struct wl_signal touch_frame;
struct wl_signal tablet_tool_axis; struct wl_signal tablet_tool_axis; // struct wlr_tablet_tool_axis_event
struct wl_signal tablet_tool_proximity; struct wl_signal tablet_tool_proximity; // struct wlr_tablet_tool_proximity_event
struct wl_signal tablet_tool_tip; struct wl_signal tablet_tool_tip; // struct wlr_tablet_tool_tip_event
struct wl_signal tablet_tool_button; struct wl_signal tablet_tool_button; // struct wlr_tablet_tool_button_event
} events; } events;
void *data; void *data;

View file

@ -36,6 +36,7 @@ struct wlr_switch {
enum wlr_switch_type { enum wlr_switch_type {
WLR_SWITCH_TYPE_LID, WLR_SWITCH_TYPE_LID,
WLR_SWITCH_TYPE_TABLET_MODE, WLR_SWITCH_TYPE_TABLET_MODE,
WLR_SWITCH_TYPE_KEYPAD_SLIDE,
}; };
enum wlr_switch_state { enum wlr_switch_state {

View file

@ -1,7 +1,7 @@
project( project(
'wlroots', 'wlroots',
'c', 'c',
version: '0.20.0-rc1', version: '0.20.0-rc3',
license: 'MIT', license: 'MIT',
meson_version: '>=1.3', meson_version: '>=1.3',
default_options: [ default_options: [

View file

@ -167,10 +167,9 @@ bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline,
etime = ETIME; etime = ETIME;
#endif #endif
uint32_t signaled_point; int ret = drmSyncobjTimelineWait(timeline->drm_fd, &timeline->handle, &point, 1, 0, flags, NULL);
int ret = drmSyncobjTimelineWait(timeline->drm_fd, &timeline->handle, &point, 1, 0, flags, &signaled_point);
if (ret != 0 && ret != -etime) { if (ret != 0 && ret != -etime) {
wlr_log_errno(WLR_ERROR, "drmSyncobjWait() failed"); wlr_log_errno(WLR_ERROR, "drmSyncobjTimelineWait() failed");
return false; return false;
} }

View file

@ -307,3 +307,68 @@ bool pixel_format_has_alpha(uint32_t fmt) {
} }
return true; return true;
} }
bool pixel_format_is_ycbcr(uint32_t format) {
switch (format) {
case DRM_FORMAT_AYUV:
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV15:
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV20:
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV24:
case DRM_FORMAT_NV30:
case DRM_FORMAT_NV42:
case DRM_FORMAT_NV61:
case DRM_FORMAT_P010:
case DRM_FORMAT_P012:
case DRM_FORMAT_P016:
case DRM_FORMAT_P030:
case DRM_FORMAT_P210:
case DRM_FORMAT_Q401:
case DRM_FORMAT_Q410:
case DRM_FORMAT_S010:
case DRM_FORMAT_S012:
case DRM_FORMAT_S016:
case DRM_FORMAT_S210:
case DRM_FORMAT_S212:
case DRM_FORMAT_S216:
case DRM_FORMAT_S410:
case DRM_FORMAT_S412:
case DRM_FORMAT_S416:
case DRM_FORMAT_UYVY:
case DRM_FORMAT_VUY101010:
case DRM_FORMAT_VUY888:
case DRM_FORMAT_VYUY:
case DRM_FORMAT_X0L0:
case DRM_FORMAT_X0L2:
case DRM_FORMAT_XVYU12_16161616:
case DRM_FORMAT_XVYU16161616:
case DRM_FORMAT_XVYU2101010:
case DRM_FORMAT_XYUV8888:
case DRM_FORMAT_Y0L0:
case DRM_FORMAT_Y0L2:
case DRM_FORMAT_Y210:
case DRM_FORMAT_Y212:
case DRM_FORMAT_Y216:
case DRM_FORMAT_Y410:
case DRM_FORMAT_Y412:
case DRM_FORMAT_Y416:
case DRM_FORMAT_YUV410:
case DRM_FORMAT_YUV411:
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YUV420_10BIT:
case DRM_FORMAT_YUV420_8BIT:
case DRM_FORMAT_YUV422:
case DRM_FORMAT_YUV444:
case DRM_FORMAT_YUYV:
case DRM_FORMAT_YVU410:
case DRM_FORMAT_YVU411:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_YVU422:
case DRM_FORMAT_YVU444:
case DRM_FORMAT_YVYU:
return true;
}
return false;
}

View file

@ -146,6 +146,40 @@ static VkSemaphore render_pass_wait_sync_file(struct wlr_vk_render_pass *pass,
return *sem_ptr; 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];
for (size_t i = 0; i < WLR_DMABUF_MAX_PLANES; i++) {
sync_file_fds[i] = -1;
}
if (!vulkan_sync_render_buffer_acquire(pass->render_buffer, sync_file_fds)) {
return false;
}
for (size_t i = 0; i < WLR_DMABUF_MAX_PLANES; i++) {
if (sync_file_fds[i] < 0) {
continue;
}
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;
}
render_wait[*render_wait_len_ptr] = (VkSemaphoreSubmitInfoKHR){
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR,
.semaphore = sem,
.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR,
};
(*render_wait_len_ptr)++;
}
return true;
}
static bool unwrap_color_transform(struct wlr_color_transform *transform, static bool unwrap_color_transform(struct wlr_color_transform *transform,
float matrix[static 9], enum wlr_color_transfer_function *tf) { float matrix[static 9], enum wlr_color_transfer_function *tf) {
if (transform == NULL) { if (transform == NULL) {
@ -308,7 +342,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
vkCmdEndRenderPass(render_cb->vk); vkCmdEndRenderPass(render_cb->vk);
size_t pass_textures_len = pass->textures.size / sizeof(struct wlr_vk_render_pass_texture); size_t pass_textures_len = pass->textures.size / sizeof(struct wlr_vk_render_pass_texture);
size_t render_wait_cap = pass_textures_len * WLR_DMABUF_MAX_PLANES; size_t render_wait_cap = (1 + pass_textures_len) * WLR_DMABUF_MAX_PLANES;
render_wait = calloc(render_wait_cap, sizeof(*render_wait)); render_wait = calloc(render_wait_cap, sizeof(*render_wait));
if (render_wait == NULL) { if (render_wait == NULL) {
wlr_log_errno(WLR_ERROR, "Allocation failed"); wlr_log_errno(WLR_ERROR, "Allocation failed");
@ -386,7 +420,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
sync_file_fds[0] = sync_file_fd; sync_file_fds[0] = sync_file_fd;
} else { } else {
struct wlr_vk_texture *texture = pass_texture->texture; struct wlr_vk_texture *texture = pass_texture->texture;
if (!vulkan_sync_foreign_texture(texture, sync_file_fds)) { if (!vulkan_sync_foreign_texture_acquire(texture, sync_file_fds)) {
wlr_log(WLR_ERROR, "Failed to wait for foreign texture DMA-BUF fence"); wlr_log(WLR_ERROR, "Failed to wait for foreign texture DMA-BUF fence");
continue; continue;
} }
@ -413,6 +447,10 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
} }
} }
if (!render_pass_wait_render_buffer(pass, render_wait, &render_wait_len)) {
wlr_log(WLR_ERROR, "Failed to wait for render buffer DMA-BUF fence");
}
// also add acquire/release barriers for the current render buffer // also add acquire/release barriers for the current render buffer
VkImageLayout src_layout = VK_IMAGE_LAYOUT_GENERAL; VkImageLayout src_layout = VK_IMAGE_LAYOUT_GENERAL;
if (!pass->render_buffer_out->transitioned) { if (!pass->render_buffer_out->transitioned) {
@ -606,8 +644,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
wl_list_insert(&stage_cb->stage_buffers, &stage_buf->link); wl_list_insert(&stage_cb->stage_buffers, &stage_buf->link);
} }
if (!vulkan_sync_render_buffer(renderer, render_buffer, render_cb, if (!vulkan_sync_render_pass_release(renderer, pass)) {
pass->signal_timeline, pass->signal_point)) {
wlr_log(WLR_ERROR, "Failed to sync render buffer"); wlr_log(WLR_ERROR, "Failed to sync render buffer");
} }
@ -822,12 +859,13 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
} }
enum wlr_color_encoding color_encoding = options->color_encoding; enum wlr_color_encoding color_encoding = options->color_encoding;
if (texture->format->is_ycbcr && color_encoding == WLR_COLOR_ENCODING_NONE) { bool is_ycbcr = vulkan_format_is_ycbcr(texture->format);
if (is_ycbcr && color_encoding == WLR_COLOR_ENCODING_NONE) {
color_encoding = WLR_COLOR_ENCODING_BT601; color_encoding = WLR_COLOR_ENCODING_BT601;
} }
enum wlr_color_range color_range = options->color_range; enum wlr_color_range color_range = options->color_range;
if (texture->format->is_ycbcr && color_range == WLR_COLOR_RANGE_NONE) { if (is_ycbcr && color_range == WLR_COLOR_RANGE_NONE) {
color_range = WLR_COLOR_RANGE_LIMITED; color_range = WLR_COLOR_RANGE_LIMITED;
} }
@ -837,7 +875,7 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
.source = WLR_VK_SHADER_SOURCE_TEXTURE, .source = WLR_VK_SHADER_SOURCE_TEXTURE,
.layout = { .layout = {
.ycbcr = { .ycbcr = {
.format = texture->format->is_ycbcr ? texture->format : NULL, .format = is_ycbcr ? texture->format : NULL,
.encoding = color_encoding, .encoding = color_encoding,
.range = color_range, .range = color_range,
}, },

View file

@ -182,37 +182,30 @@ static const struct wlr_vk_format formats[] = {
{ {
.drm = DRM_FORMAT_UYVY, .drm = DRM_FORMAT_UYVY,
.vk = VK_FORMAT_B8G8R8G8_422_UNORM, .vk = VK_FORMAT_B8G8R8G8_422_UNORM,
.is_ycbcr = true,
}, },
{ {
.drm = DRM_FORMAT_YUYV, .drm = DRM_FORMAT_YUYV,
.vk = VK_FORMAT_G8B8G8R8_422_UNORM, .vk = VK_FORMAT_G8B8G8R8_422_UNORM,
.is_ycbcr = true,
}, },
{ {
.drm = DRM_FORMAT_NV12, .drm = DRM_FORMAT_NV12,
.vk = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, .vk = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
.is_ycbcr = true,
}, },
{ {
.drm = DRM_FORMAT_NV16, .drm = DRM_FORMAT_NV16,
.vk = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, .vk = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
.is_ycbcr = true,
}, },
{ {
.drm = DRM_FORMAT_YUV420, .drm = DRM_FORMAT_YUV420,
.vk = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, .vk = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
.is_ycbcr = true,
}, },
{ {
.drm = DRM_FORMAT_YUV422, .drm = DRM_FORMAT_YUV422,
.vk = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, .vk = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
.is_ycbcr = true,
}, },
{ {
.drm = DRM_FORMAT_YUV444, .drm = DRM_FORMAT_YUV444,
.vk = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, .vk = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
.is_ycbcr = true,
}, },
// 3PACK16 formats split the memory in three 16-bit words, so they have an // 3PACK16 formats split the memory in three 16-bit words, so they have an
// inverted channel order compared to DRM formats. // inverted channel order compared to DRM formats.
@ -220,27 +213,22 @@ static const struct wlr_vk_format formats[] = {
{ {
.drm = DRM_FORMAT_P010, .drm = DRM_FORMAT_P010,
.vk = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, .vk = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
.is_ycbcr = true,
}, },
{ {
.drm = DRM_FORMAT_P210, .drm = DRM_FORMAT_P210,
.vk = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, .vk = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
.is_ycbcr = true,
}, },
{ {
.drm = DRM_FORMAT_P012, .drm = DRM_FORMAT_P012,
.vk = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, .vk = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16,
.is_ycbcr = true,
}, },
{ {
.drm = DRM_FORMAT_P016, .drm = DRM_FORMAT_P016,
.vk = VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, .vk = VK_FORMAT_G16_B16R16_2PLANE_420_UNORM,
.is_ycbcr = true,
}, },
{ {
.drm = DRM_FORMAT_Q410, .drm = DRM_FORMAT_Q410,
.vk = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, .vk = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16,
.is_ycbcr = true,
}, },
#endif #endif
// TODO: add DRM_FORMAT_NV24/VK_FORMAT_G8_B8R8_2PLANE_444_UNORM (requires // TODO: add DRM_FORMAT_NV24/VK_FORMAT_G8_B8R8_2PLANE_444_UNORM (requires
@ -446,7 +434,7 @@ static bool query_modifier_support(struct wlr_vk_device *dev,
// check that specific modifier for render usage // check that specific modifier for render usage
const char *errmsg = "unknown error"; const char *errmsg = "unknown error";
if ((m.drmFormatModifierTilingFeatures & render_features) == render_features && if ((m.drmFormatModifierTilingFeatures & render_features) == render_features &&
!props->format.is_ycbcr) { !vulkan_format_is_ycbcr(&props->format)) {
struct wlr_vk_format_modifier_props p = {0}; struct wlr_vk_format_modifier_props p = {0};
bool supported = false; bool supported = false;
if (query_modifier_usage_support(dev, props->format.vk, if (query_modifier_usage_support(dev, props->format.vk,
@ -477,7 +465,7 @@ static bool query_modifier_support(struct wlr_vk_device *dev,
// check that specific modifier for texture usage // check that specific modifier for texture usage
errmsg = "unknown error"; errmsg = "unknown error";
VkFormatFeatureFlags features = dma_tex_features; VkFormatFeatureFlags features = dma_tex_features;
if (props->format.is_ycbcr) { if (vulkan_format_is_ycbcr(&props->format)) {
features |= ycbcr_tex_features; features |= ycbcr_tex_features;
} }
if ((m.drmFormatModifierTilingFeatures & features) == features) { if ((m.drmFormatModifierTilingFeatures & features) == features) {
@ -522,7 +510,7 @@ static bool query_modifier_support(struct wlr_vk_device *dev,
void vulkan_format_props_query(struct wlr_vk_device *dev, void vulkan_format_props_query(struct wlr_vk_device *dev,
const struct wlr_vk_format *format) { const struct wlr_vk_format *format) {
if (format->is_ycbcr && !dev->sampler_ycbcr_conversion) { if (vulkan_format_is_ycbcr(format) && !dev->sampler_ycbcr_conversion) {
return; return;
} }
@ -551,7 +539,7 @@ void vulkan_format_props_query(struct wlr_vk_device *dev,
char shm_texture_status[256]; char shm_texture_status[256];
const char *errmsg = "unknown error"; const char *errmsg = "unknown error";
if ((fmtp.formatProperties.optimalTilingFeatures & shm_tex_features) == shm_tex_features && if ((fmtp.formatProperties.optimalTilingFeatures & shm_tex_features) == shm_tex_features &&
!format->is_ycbcr && format_info != NULL) { !vulkan_format_is_ycbcr(format) && format_info != NULL) {
VkImageFormatProperties ifmtp; VkImageFormatProperties ifmtp;
bool supported = false, has_mutable_srgb = false; bool supported = false, has_mutable_srgb = false;
if (query_shm_support(dev, format->vk, format->vk_srgb, &ifmtp, &errmsg)) { if (query_shm_support(dev, format->vk, format->vk_srgb, &ifmtp, &errmsg)) {
@ -621,3 +609,7 @@ const struct wlr_vk_format_modifier_props *vulkan_format_props_find_modifier(
} }
return NULL; return NULL;
} }
bool vulkan_format_is_ycbcr(const struct wlr_vk_format *format) {
return pixel_format_is_ycbcr(format->drm);
}

View file

@ -968,13 +968,11 @@ static struct wlr_vk_render_buffer *get_render_buffer(
return buffer; return buffer;
} }
bool vulkan_sync_foreign_texture(struct wlr_vk_texture *texture, static bool buffer_export_sync_file(struct wlr_vk_renderer *renderer, struct wlr_buffer *buffer,
int sync_file_fds[static WLR_DMABUF_MAX_PLANES]) { uint32_t flags, int sync_file_fds[static WLR_DMABUF_MAX_PLANES]) {
struct wlr_vk_renderer *renderer = texture->renderer;
struct wlr_dmabuf_attributes dmabuf = {0}; struct wlr_dmabuf_attributes dmabuf = {0};
if (!wlr_buffer_get_dmabuf(texture->buffer, &dmabuf)) { if (!wlr_buffer_get_dmabuf(buffer, &dmabuf)) {
wlr_log(WLR_ERROR, "Failed to get texture DMA-BUF"); wlr_log(WLR_ERROR, "wlr_buffer_get_dmabuf() failed");
return false; return false;
} }
@ -984,7 +982,7 @@ bool vulkan_sync_foreign_texture(struct wlr_vk_texture *texture,
for (int i = 0; i < dmabuf.n_planes; i++) { for (int i = 0; i < dmabuf.n_planes; i++) {
struct pollfd pollfd = { struct pollfd pollfd = {
.fd = dmabuf.fd[i], .fd = dmabuf.fd[i],
.events = POLLIN, .events = (flags & DMA_BUF_SYNC_WRITE) ? POLLOUT : POLLIN,
}; };
int timeout_ms = 1000; int timeout_ms = 1000;
int ret = poll(&pollfd, 1, timeout_ms); int ret = poll(&pollfd, 1, timeout_ms);
@ -1001,7 +999,7 @@ bool vulkan_sync_foreign_texture(struct wlr_vk_texture *texture,
} }
for (int i = 0; i < dmabuf.n_planes; i++) { for (int i = 0; i < dmabuf.n_planes; i++) {
int sync_file_fd = dmabuf_export_sync_file(dmabuf.fd[i], DMA_BUF_SYNC_READ); int sync_file_fd = dmabuf_export_sync_file(dmabuf.fd[i], flags);
if (sync_file_fd < 0) { if (sync_file_fd < 0) {
wlr_log(WLR_ERROR, "Failed to extract DMA-BUF fence"); wlr_log(WLR_ERROR, "Failed to extract DMA-BUF fence");
return false; return false;
@ -1013,12 +1011,40 @@ bool vulkan_sync_foreign_texture(struct wlr_vk_texture *texture,
return true; return true;
} }
bool vulkan_sync_render_buffer(struct wlr_vk_renderer *renderer, bool vulkan_sync_foreign_texture_acquire(struct wlr_vk_texture *texture,
struct wlr_vk_render_buffer *render_buffer, struct wlr_vk_command_buffer *cb, int sync_file_fds[static WLR_DMABUF_MAX_PLANES]) {
struct wlr_drm_syncobj_timeline *signal_timeline, uint64_t signal_point) { return buffer_export_sync_file(texture->renderer, texture->buffer, DMA_BUF_SYNC_READ, sync_file_fds);
VkResult res; }
if (!renderer->dev->implicit_sync_interop && signal_timeline == NULL) { bool vulkan_sync_render_buffer_acquire(struct wlr_vk_render_buffer *render_buffer,
int sync_file_fds[static WLR_DMABUF_MAX_PLANES]) {
return buffer_export_sync_file(render_buffer->renderer, render_buffer->wlr_buffer,
DMA_BUF_SYNC_WRITE, sync_file_fds);
}
static bool buffer_import_sync_file(struct wlr_buffer *buffer, uint32_t flags, int sync_file_fd) {
struct wlr_dmabuf_attributes dmabuf = {0};
if (!wlr_buffer_get_dmabuf(buffer, &dmabuf)) {
wlr_log(WLR_ERROR, "wlr_buffer_get_dmabuf() failed");
return false;
}
for (int i = 0; i < dmabuf.n_planes; i++) {
if (!dmabuf_import_sync_file(dmabuf.fd[i], flags,
sync_file_fd)) {
return false;
}
}
return true;
}
bool vulkan_sync_render_pass_release(struct wlr_vk_renderer *renderer,
struct wlr_vk_render_pass *pass) {
VkResult res;
struct wlr_vk_command_buffer *cb = pass->command_buffer;
if (!renderer->dev->implicit_sync_interop && pass->signal_timeline == NULL) {
// We have no choice but to block here sadly // We have no choice but to block here sadly
return vulkan_wait_command_buffer(cb, renderer); return vulkan_wait_command_buffer(cb, renderer);
} }
@ -1040,21 +1066,19 @@ bool vulkan_sync_render_buffer(struct wlr_vk_renderer *renderer,
} }
bool ok = false; bool ok = false;
if (signal_timeline != NULL) { if (pass->signal_timeline != NULL) {
if (!wlr_drm_syncobj_timeline_import_sync_file(signal_timeline, if (!wlr_drm_syncobj_timeline_import_sync_file(pass->signal_timeline,
signal_point, sync_file_fd)) { pass->signal_point, sync_file_fd)) {
goto out; goto out;
} }
} else { } else {
struct wlr_dmabuf_attributes dmabuf = {0}; if (!buffer_import_sync_file(pass->render_buffer->wlr_buffer, DMA_BUF_SYNC_WRITE, sync_file_fd)) {
if (!wlr_buffer_get_dmabuf(render_buffer->wlr_buffer, &dmabuf)) {
wlr_log(WLR_ERROR, "wlr_buffer_get_dmabuf failed");
goto out; goto out;
} }
for (int i = 0; i < dmabuf.n_planes; i++) { struct wlr_vk_render_pass_texture *pass_texture;
if (!dmabuf_import_sync_file(dmabuf.fd[i], DMA_BUF_SYNC_WRITE, wl_array_for_each(pass_texture, &pass->textures) {
sync_file_fd)) { if (!buffer_import_sync_file(pass_texture->texture->buffer, DMA_BUF_SYNC_READ, sync_file_fd)) {
goto out; goto out;
} }
} }
@ -1630,8 +1654,8 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) {
static bool pipeline_layout_key_equals( static bool pipeline_layout_key_equals(
const struct wlr_vk_pipeline_layout_key *a, const struct wlr_vk_pipeline_layout_key *a,
const struct wlr_vk_pipeline_layout_key *b) { const struct wlr_vk_pipeline_layout_key *b) {
assert(!a->ycbcr.format || a->ycbcr.format->is_ycbcr); assert(!a->ycbcr.format || vulkan_format_is_ycbcr(a->ycbcr.format));
assert(!b->ycbcr.format || b->ycbcr.format->is_ycbcr); assert(!b->ycbcr.format || vulkan_format_is_ycbcr(b->ycbcr.format));
if (a->filter_mode != b->filter_mode) { if (a->filter_mode != b->filter_mode) {
return false; return false;
@ -2039,8 +2063,8 @@ struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout(
}; };
sampler_create_info.pNext = &conversion_info; sampler_create_info.pNext = &conversion_info;
} else { } else {
assert(key->ycbcr.encoding == WLR_COLOR_ENCODING_NONE); assert(key->ycbcr.encoding == WLR_COLOR_ENCODING_NONE || key->ycbcr.encoding == WLR_COLOR_ENCODING_IDENTITY);
assert(key->ycbcr.range == WLR_COLOR_RANGE_NONE); assert(key->ycbcr.range == WLR_COLOR_RANGE_NONE || key->ycbcr.range == WLR_COLOR_RANGE_FULL);
} }
res = vkCreateSampler(renderer->dev->dev, &sampler_create_info, NULL, &pipeline_layout->sampler); res = vkCreateSampler(renderer->dev->dev, &sampler_create_info, NULL, &pipeline_layout->sampler);

View file

@ -297,7 +297,7 @@ struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_text
.components.r = VK_COMPONENT_SWIZZLE_IDENTITY, .components.r = VK_COMPONENT_SWIZZLE_IDENTITY,
.components.g = VK_COMPONENT_SWIZZLE_IDENTITY, .components.g = VK_COMPONENT_SWIZZLE_IDENTITY,
.components.b = VK_COMPONENT_SWIZZLE_IDENTITY, .components.b = VK_COMPONENT_SWIZZLE_IDENTITY,
.components.a = texture->has_alpha || texture->format->is_ycbcr .components.a = texture->has_alpha || vulkan_format_is_ycbcr(texture->format)
? VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_IDENTITY
: VK_COMPONENT_SWIZZLE_ONE, : VK_COMPONENT_SWIZZLE_ONE,
.subresourceRange = (VkImageSubresourceRange){ .subresourceRange = (VkImageSubresourceRange){
@ -311,7 +311,7 @@ struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_text
}; };
VkSamplerYcbcrConversionInfo ycbcr_conversion_info; VkSamplerYcbcrConversionInfo ycbcr_conversion_info;
if (texture->format->is_ycbcr) { if (vulkan_format_is_ycbcr(texture->format)) {
assert(pipeline_layout->ycbcr.conversion != VK_NULL_HANDLE); assert(pipeline_layout->ycbcr.conversion != VK_NULL_HANDLE);
ycbcr_conversion_info = (VkSamplerYcbcrConversionInfo){ ycbcr_conversion_info = (VkSamplerYcbcrConversionInfo){
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, .sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
@ -355,7 +355,7 @@ struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_text
static void texture_set_format(struct wlr_vk_texture *texture, static void texture_set_format(struct wlr_vk_texture *texture,
const struct wlr_vk_format *format, bool has_mutable_srgb) { const struct wlr_vk_format *format, bool has_mutable_srgb) {
assert(!(format->is_ycbcr && has_mutable_srgb)); assert(!(vulkan_format_is_ycbcr(format) && has_mutable_srgb));
texture->format = format; texture->format = format;
texture->using_mutable_srgb = has_mutable_srgb; texture->using_mutable_srgb = has_mutable_srgb;
@ -366,7 +366,7 @@ static void texture_set_format(struct wlr_vk_texture *texture,
texture->has_alpha = pixel_format_has_alpha(format->drm); texture->has_alpha = pixel_format_has_alpha(format->drm);
} else { } else {
// We don't have format info for multi-planar formats // We don't have format info for multi-planar formats
assert(texture->format->is_ycbcr); assert(vulkan_format_is_ycbcr(texture->format));
} }
} }
@ -378,7 +378,7 @@ static struct wlr_texture *vulkan_texture_from_pixels(
const struct wlr_vk_format_props *fmt = const struct wlr_vk_format_props *fmt =
vulkan_format_props_from_drm(renderer->dev, drm_fmt); vulkan_format_props_from_drm(renderer->dev, drm_fmt);
if (fmt == NULL || fmt->format.is_ycbcr) { if (fmt == NULL || vulkan_format_is_ycbcr(&fmt->format)) {
char *format_name = drmGetFormatName(drm_fmt); char *format_name = drmGetFormatName(drm_fmt);
wlr_log(WLR_ERROR, "Unsupported pixel format %s (0x%08"PRIX32")", wlr_log(WLR_ERROR, "Unsupported pixel format %s (0x%08"PRIX32")",
format_name, drm_fmt); format_name, drm_fmt);

View file

@ -109,14 +109,11 @@ bool wlr_buffer_get_shm(struct wlr_buffer *buffer,
bool wlr_buffer_is_opaque(struct wlr_buffer *buffer) { bool wlr_buffer_is_opaque(struct wlr_buffer *buffer) {
void *data; void *data;
uint32_t format; uint32_t format = buffer_get_drm_format(buffer);
size_t stride; size_t stride;
struct wlr_dmabuf_attributes dmabuf;
struct wlr_shm_attributes shm; if (format != DRM_FORMAT_INVALID) {
if (wlr_buffer_get_dmabuf(buffer, &dmabuf)) { // pass
format = dmabuf.format;
} else if (wlr_buffer_get_shm(buffer, &shm)) {
format = shm.format;
} else if (wlr_buffer_begin_data_ptr_access(buffer, } else if (wlr_buffer_begin_data_ptr_access(buffer,
WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) { WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &format, &stride)) {
bool opaque = false; bool opaque = false;
@ -135,3 +132,15 @@ bool wlr_buffer_is_opaque(struct wlr_buffer *buffer) {
return !pixel_format_has_alpha(format); return !pixel_format_has_alpha(format);
} }
uint32_t buffer_get_drm_format(struct wlr_buffer *buffer) {
uint32_t format = DRM_FORMAT_INVALID;
struct wlr_dmabuf_attributes dmabuf;
struct wlr_shm_attributes shm;
if (wlr_buffer_get_dmabuf(buffer, &dmabuf)) {
format = dmabuf.format;
} else if (wlr_buffer_get_shm(buffer, &shm)) {
format = shm.format;
}
return format;
}

View file

@ -173,8 +173,6 @@ static void source_update_buffer_constraints(struct scene_node_source *source,
} }
static bool output_test(struct wlr_output *output, const struct wlr_output_state *state) { static bool output_test(struct wlr_output *output, const struct wlr_output_state *state) {
struct scene_node_source *source = wl_container_of(output, source, output);
uint32_t supported = uint32_t supported =
WLR_OUTPUT_STATE_BACKEND_OPTIONAL | WLR_OUTPUT_STATE_BACKEND_OPTIONAL |
WLR_OUTPUT_STATE_BUFFER | WLR_OUTPUT_STATE_BUFFER |

View file

@ -1,6 +1,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <wlr/types/wlr_scene.h> #include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_layer_shell_v1.h> #include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/util/edges.h>
static void scene_layer_surface_handle_tree_destroy( static void scene_layer_surface_handle_tree_destroy(
struct wl_listener *listener, void *data) { struct wl_listener *listener, void *data) {
@ -21,36 +22,23 @@ static void scene_layer_surface_handle_layer_surface_destroy(
static void layer_surface_exclusive_zone( static void layer_surface_exclusive_zone(
struct wlr_layer_surface_v1_state *state, struct wlr_layer_surface_v1_state *state,
enum wlr_edges edge,
struct wlr_box *usable_area) { struct wlr_box *usable_area) {
switch (state->anchor) { switch (edge) {
case ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP: case WLR_EDGE_NONE:
case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | return;
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | case WLR_EDGE_TOP:
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT):
// Anchor top
usable_area->y += state->exclusive_zone + state->margin.top; usable_area->y += state->exclusive_zone + state->margin.top;
usable_area->height -= state->exclusive_zone + state->margin.top; usable_area->height -= state->exclusive_zone + state->margin.top;
break; break;
case ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM: case WLR_EDGE_BOTTOM:
case (ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT):
// Anchor bottom
usable_area->height -= state->exclusive_zone + state->margin.bottom; usable_area->height -= state->exclusive_zone + state->margin.bottom;
break; break;
case ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT: case WLR_EDGE_LEFT:
case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT):
// Anchor left
usable_area->x += state->exclusive_zone + state->margin.left; usable_area->x += state->exclusive_zone + state->margin.left;
usable_area->width -= state->exclusive_zone + state->margin.left; usable_area->width -= state->exclusive_zone + state->margin.left;
break; break;
case ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT: case WLR_EDGE_RIGHT:
case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT):
// Anchor right
usable_area->width -= state->exclusive_zone + state->margin.right; usable_area->width -= state->exclusive_zone + state->margin.right;
break; break;
} }
@ -121,7 +109,8 @@ void wlr_scene_layer_surface_v1_configure(
wlr_layer_surface_v1_configure(layer_surface, box.width, box.height); wlr_layer_surface_v1_configure(layer_surface, box.width, box.height);
if (layer_surface->surface->mapped && state->exclusive_zone > 0) { if (layer_surface->surface->mapped && state->exclusive_zone > 0) {
layer_surface_exclusive_zone(state, usable_area); enum wlr_edges edge = wlr_layer_surface_v1_get_exclusive_edge(layer_surface);
layer_surface_exclusive_zone(state, edge, usable_area);
} }
} }

View file

@ -2086,8 +2086,12 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout(
return SCANOUT_INELIGIBLE; return SCANOUT_INELIGIBLE;
} }
if (buffer->color_encoding != WLR_COLOR_ENCODING_NONE || bool is_color_repr_none = buffer->color_encoding == WLR_COLOR_ENCODING_NONE &&
buffer->color_range != WLR_COLOR_RANGE_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; return SCANOUT_INELIGIBLE;
} }

View file

@ -1,13 +1,17 @@
#include <assert.h> #include <assert.h>
#include <drm_fourcc.h>
#include <stdlib.h> #include <stdlib.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_color_representation_v1.h> #include <wlr/types/wlr_color_representation_v1.h>
#include <wlr/util/addon.h> #include <wlr/util/addon.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "color-representation-v1-protocol.h" #include "color-representation-v1-protocol.h"
#include "render/pixel_format.h"
#include "types/wlr_buffer.h"
#include "util/mem.h" #include "util/mem.h"
#define WP_COLOR_REPRESENTATION_VERSION 1 #define WP_COLOR_REPRESENTATION_VERSION 1
@ -230,8 +234,44 @@ static void color_repr_manager_handle_destroy(struct wl_client *client,
wl_resource_destroy(resource); wl_resource_destroy(resource);
} }
static void surface_synced_commit(struct wlr_surface_synced *synced) {
struct wlr_color_representation_v1 *color_repr = wl_container_of(synced, color_repr, synced);
if (color_repr->current.coefficients == 0 && color_repr->current.range == 0) {
return;
}
uint32_t drm_format = DRM_FORMAT_INVALID;
if (color_repr->surface->buffer){
drm_format = buffer_get_drm_format(&color_repr->surface->buffer->base);
}
if (drm_format == DRM_FORMAT_INVALID) {
return;
}
bool is_ycbcr = pixel_format_is_ycbcr(drm_format);
bool is_identity_full =
color_repr->current.coefficients == WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_IDENTITY &&
color_repr->current.range == WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_FULL;
if (is_ycbcr) {
if (is_identity_full) {
wl_resource_post_error(color_repr->resource,
WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_PIXEL_FORMAT,
"unexpected encoding/range for yuv");
}
} else /* rgb */ {
if (!is_identity_full) {
wl_resource_post_error(color_repr->resource,
WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_PIXEL_FORMAT,
"unexpected encoding/range for rgb");
}
}
}
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_color_representation_v1_surface_state), .state_size = sizeof(struct wlr_color_representation_v1_surface_state),
.commit = surface_synced_commit
}; };
static struct wlr_color_representation_v1 *color_repr_from_surface( static struct wlr_color_representation_v1 *color_repr_from_surface(
@ -276,6 +316,7 @@ static void color_repr_manager_handle_get_surface(struct wl_client *client,
} }
color_repr->manager = manager_from_resource(manager_resource); color_repr->manager = manager_from_resource(manager_resource);
color_repr->surface = surface;
if (!wlr_surface_synced_init(&color_repr->synced, surface, if (!wlr_surface_synced_init(&color_repr->synced, surface,
&surface_synced_impl, &color_repr->pending, &color_repr->current)) { &surface_synced_impl, &color_repr->pending, &color_repr->current)) {
@ -427,6 +468,10 @@ struct wlr_color_representation_manager_v1 *wlr_color_representation_manager_v1_
struct wlr_color_representation_v1_coeffs_and_range coeffs_and_ranges[COEFFICIENTS_LEN * RANGES_LEN]; struct wlr_color_representation_v1_coeffs_and_range coeffs_and_ranges[COEFFICIENTS_LEN * RANGES_LEN];
size_t coeffs_and_ranges_len = 0; size_t coeffs_and_ranges_len = 0;
coeffs_and_ranges[coeffs_and_ranges_len++] = (struct wlr_color_representation_v1_coeffs_and_range){
.coeffs = WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_IDENTITY,
.range = WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_FULL,
};
for (size_t i = 0; i < COEFFICIENTS_LEN; i++) { for (size_t i = 0; i < COEFFICIENTS_LEN; i++) {
enum wp_color_representation_surface_v1_coefficients coeffs = coefficients[i]; enum wp_color_representation_surface_v1_coefficients coeffs = coefficients[i];
enum wlr_color_encoding enc = wlr_color_representation_v1_color_encoding_to_wlr(coeffs); enum wlr_color_encoding enc = wlr_color_representation_v1_color_encoding_to_wlr(coeffs);

View file

@ -956,7 +956,7 @@ static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) {
static void handle_tablet_tool_button(struct wl_listener *listener, static void handle_tablet_tool_button(struct wl_listener *listener,
void *data) { void *data) {
struct wlr_tablet_tool_button *event = data; struct wlr_tablet_tool_button_event *event = data;
struct wlr_cursor_device *device; struct wlr_cursor_device *device;
device = wl_container_of(listener, device, tablet_tool_button); device = wl_container_of(listener, device, tablet_tool_button);
wl_signal_emit_mutable(&device->cursor->events.tablet_tool_button, event); wl_signal_emit_mutable(&device->cursor->events.tablet_tool_button, event);

View file

@ -308,7 +308,7 @@ void wlr_keyboard_group_remove_keyboard(struct wlr_keyboard_group *group,
void wlr_keyboard_group_destroy(struct wlr_keyboard_group *group) { void wlr_keyboard_group_destroy(struct wlr_keyboard_group *group) {
struct keyboard_group_device *device, *tmp_device; struct keyboard_group_device *device, *tmp_device;
wl_list_for_each_safe(device, tmp_device, &group->devices, link) { wl_list_for_each_safe(device, tmp_device, &group->devices, link) {
wlr_keyboard_group_remove_keyboard(group, device->keyboard); remove_keyboard_group_device(device);
} }
// Now group->keys might not be empty if a wlr_keyboard has emitted // Now group->keys might not be empty if a wlr_keyboard has emitted

View file

@ -381,13 +381,15 @@ static bool source_get_targets(struct wlr_xwm_selection *selection,
free(mime_type); free(mime_type);
break; break;
} }
*mime_type_ptr = mime_type;
xcb_atom_t *atom_ptr = xcb_atom_t *atom_ptr =
wl_array_add(mime_types_atoms, sizeof(*atom_ptr)); wl_array_add(mime_types_atoms, sizeof(*atom_ptr));
if (atom_ptr == NULL) { if (atom_ptr == NULL) {
mime_types->size -= sizeof(*mime_type_ptr);
free(mime_type);
break; break;
} }
*mime_type_ptr = mime_type;
*atom_ptr = value[i]; *atom_ptr = value[i];
} }
} }

View file

@ -1,5 +1,6 @@
#include <assert.h> #include <assert.h>
#include <drm_fourcc.h> #include <drm_fourcc.h>
#include <poll.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <wlr/types/wlr_buffer.h> #include <wlr/types/wlr_buffer.h>
@ -2881,5 +2882,20 @@ xcb_connection_t *wlr_xwayland_get_xwm_connection(
} }
void xwm_schedule_flush(struct wlr_xwm *xwm) { void xwm_schedule_flush(struct wlr_xwm *xwm) {
struct pollfd pollfd = {
.fd = xcb_get_file_descriptor(xwm->xcb_conn),
.events = POLLOUT,
};
if (poll(&pollfd, 1, 0) < 0) {
wlr_log(WLR_ERROR, "poll() failed");
return;
}
// If we can write immediately, do so
if (pollfd.revents & POLLOUT) {
xcb_flush(xwm->xcb_conn);
return;
}
wl_event_source_fd_update(xwm->event_source, WL_EVENT_READABLE | WL_EVENT_WRITABLE); wl_event_source_fd_update(xwm->event_source, WL_EVENT_READABLE | WL_EVENT_WRITABLE);
} }