Compare commits

..

27 commits

Author SHA1 Message Date
Simon Ser
5bc39071d1 build: bump version to 0.18.1 2024-09-20 12:51:54 +02:00
Simon Ser
6f2ce4766f render/vulkan: use non-coherent memory for read_pixels()
The spec for VkMemoryPropertyFlagBits says:

> device coherent accesses may be slower than equivalent accesses
> without device coherence [...] it is generally inadvisable to
> use device coherent or device uncached memory except when really
> needed

We don't really need coherent memory so let's not require it and
invalidate the memory range after mapping instead.

Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3868
(cherry picked from commit 52dce29e06)
2024-08-23 13:42:57 -04:00
Simon Ser
f43ac6cf9c backend/drm: use CRTCs in-order
When lighting up a new connector, we'd use the last CRTC instead of the
first one. This causes issues because drivers have the expectation that
userspace will match CRTCs to connectors in-order [1].

The order has regressed a long time ago in 5b13b8a12c ("backend/drm:
consider continue not using resources"). That commit was a fix to
avoid moving a connector between CRTCs [2]. Revert that commit and
use a different approach: even if we've found a solution, always try
not using a CRTC in the hope that we'll find another solution with
less CRTC replacements.

[1]: https://lore.kernel.org/dri-devel/20240612141903.17219-2-ville.syrjala@linux.intel.com/
[2]: https://github.com/swaywm/wlroots/issues/1230

Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3098
(cherry picked from commit d2a5dbe104)
2024-08-23 09:30:33 -04:00
Kirill Primak
0a4cd88637 scene: resize damage ring on geometry update
(cherry picked from commit cf93d31736)
2024-08-23 09:30:19 -04:00
Kirill Primak
b79fc11df8 scene: update output geom on commit after dropping pending damage
Otherwise the whole output damage gets ignored.

(cherry picked from commit 62cc96b3a4)
2024-08-23 09:30:07 -04:00
Dudemanguy
1f96bcc1db backend/drm: fix a use-after-free
The page_flip can be destroyed, but it is unconditionally accessed later
on when setting present_flags. Fix this by simply setting the
present_flags before the page_flip gets destroyed.

(cherry picked from commit 3d2f09bace)
2024-08-23 09:29:52 -04:00
zhoulei
0992422493 xwayland/xwm: listen shell destroy signal
Otherwise we got invaild write in wl_list_remove.

Fixes: e209fe2d0 ("Fix memory leak in xwayland.c")

Signed-off-by: zhoulei <zhoulei@kylinos.cn>
(cherry picked from commit 2c64f36e88)
2024-08-23 09:29:38 -04:00
Leonardo Hernández Hernández
4900daa787 linux-drm-syncobj-v1: actually use the requested version
(cherry picked from commit baaec88e2f)
2024-08-23 09:29:27 -04:00
Alexander Orzechowski
72a290ba01 wlr_scene: Fix WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT when output is transformed
(cherry picked from commit 4f1104654f)
2024-08-15 11:27:42 -04:00
Alexander Orzechowski
055c0d28d1 wlr_scene: Don't special case swapchain buffers
This fixes direct scanout VRR. As direct scanout buffers are not part
of the swapchain, we would mistakenly union instead of subtract the damage
meaning it will just accumulate indefinitely.

The reason for this existing in the first place is for compositors that
might want to sidestep scene and commit their own buffers to the output.
In this case, scene could theoretically acknowledge that and update the
damage. Except, this really didn't work because WLR_OUTPUT_STATE_DAMAGE
would need to be defined which is optional. This patch also properly
acknowledges commits without damage.

In the use case of a weird compositor that might want to sidestep scene,
they can just trash the damage ring themselves.

Fixes: #3871
(cherry picked from commit 14e1987f50)
2024-08-15 11:27:36 -04:00
Alexander Orzechowski
a4cafc1ef5 wlr_scene: Inline output_state_apply_damage
(cherry picked from commit 3e1358fec9)
2024-08-15 11:27:28 -04:00
Alexander Orzechowski
f9de859194 wlr_scene: Immediately apply pending output commit damage
There were two problems with the old implementation:
1. wlr_scene_output_commit would bail early if a frame wasn't requested
and there was no commit damage, however commit damage could never accumulate
until rendering happens. The check was subtly wrong as a result.
2. Previously, we would fill the pending commit damage based on the
current state of the damage ring. However, during direct scanout, the
damage would accumulate which would mean we would submit damage from
previous frames even if we didn't need to.

(cherry picked from commit 147c5c37e3)
2024-08-15 11:27:21 -04:00
Alexander Orzechowski
43388cd277 wlr_scene: Funnel all damage operations through scene_output_damage
We want to add logic to this function later

(cherry picked from commit 78dfa4f06d)
2024-08-15 11:27:12 -04:00
Isaac Freund
89e1ea130d backend/drm: don't set vsync present flag if page flip was async
(cherry picked from commit 08495d2596)
2024-08-15 11:13:05 -04:00
Kirill Primak
b4bec0cd3a backend/wayland: process initial events from globals correctly
Previous logic could lead wlr_wl_backend.drm_render_name being written
to twice, causing a memory leak. This commit fixes the race condition.

(cherry picked from commit 3103ea3af9)
2024-08-15 11:06:50 -04:00
Kirill Primak
7df7b0e092 linux-drm-syncobj: add missing decls in the header
(cherry picked from commit ee21deb458)
2024-08-15 11:06:02 -04:00
Kirill Primak
a095120b7d pointer-constraints: don't init/finish current/pending states
wlr_surface_synced does it automatically.

Reported-by: llyyr <llyyr.public@gmail.com>
(cherry picked from commit 70c99460ca)
2024-08-15 11:05:44 -04:00
Kirill Primak
9e107e3c77 xdg-popup: don't set a role resource destroy handler
wlr_xdg_surface tracks role resource destruction itself.

(cherry picked from commit c52e01e85f)
2024-08-15 11:05:32 -04:00
Consolatis
490769f2a6 ext-foreign-toplevel-list: use correct interface and add missing handler
Without this patch, a client calling handle.destroy() will trigger
an assert in libwayland due to a NULL pointer for the destroy handler.

Also implement a missing .destroy handler for the manager itself
and delay destruction of the manager resource from the .stop handler
to the .destroy handler.

(cherry picked from commit adf9d8b0be)
2024-08-15 11:05:20 -04:00
project-repo
2b8f94cf09 Fix memory leak in xwayland.c
(cherry picked from commit e209fe2d05)
2024-08-12 10:08:27 -04:00
project-repo
52834f29ad Fix memory leak in drm.c
(cherry picked from commit 3cae2a2c01)
2024-08-12 10:08:20 -04:00
Alexander Orzechowski
03f06207f0 wlr_scene: Force blend mode to PREMULTIPLIED if calculate visibility is disabled
We do it here so WLR_SCENE_HIGHLIGHT_TRANSPARENT_REGION doesn't break

(cherry picked from commit 4481c6b243)
2024-08-06 08:09:40 -04:00
Kirill Primak
81a08aeeb0 output-power-management: send zwlr_output_power_v1.failed on output destroy
From the event description:

This event indicates that the output power management mode control is no
longer valid. This can happen for a number of reasons, including:
<...>
- The output disappeared

(cherry picked from commit de574ac098)
2024-08-06 08:09:28 -04:00
chenyongxing
6cc80472cb render/vulkan: Fix draw rect clip region invalid in blend none mod
(cherry picked from commit 015bb8512e)
2024-08-06 08:09:15 -04:00
Isaac Freund
2005cc0fd6 docs: update comments for wlr_output API changes
The old wlr_output_{commit,test}() functions are still mentioned in
multiple places.

(cherry picked from commit 7550e483ae)
2024-07-15 09:58:22 -04:00
Isaac Freund
7d0f337a35 wlr_output: remove dead function
(cherry picked from commit 2a8a23c467)
2024-07-15 09:58:22 -04:00
Bill Li
4534421279 ci: use package x11-servers/xwayland instead of x11-servers/xwayland-devel
(cherry picked from commit 22adc65586)
2024-07-15 09:58:22 -04:00
323 changed files with 3615 additions and 13452 deletions

View file

@ -20,13 +20,8 @@ packages:
- xwayland-dev
- libseat-dev
- hwdata-dev
# for docs
- go
- zip
sources:
- https://gitlab.freedesktop.org/wlroots/wlroots.git
artifacts:
- public.zip
tasks:
- setup: |
cd wlroots
@ -42,16 +37,3 @@ tasks:
- tinywl: |
cd wlroots/tinywl
make
- docs: |
go install 'codeberg.org/emersion/gyosu@latest'
include_dir="$(echo /usr/local/include/wlroots-*)"
~/go/bin/gyosu \
-DWLR_USE_UNSTABLE \
$(pkg-config --cflags-only-I $(basename "$include_dir")) \
-Iwlroots/build/protocol/ \
-fexported-symbols='wlr_*' -fexported-symbols='WLR_*' \
-ffile-prefix-map="$include_dir/"= \
-fsite-name=wlroots \
-o public \
"$include_dir/wlr/"
zip -r ~/public.zip public/

View file

@ -41,10 +41,9 @@ tasks:
cd wlroots/build-gcc/tinywl
sudo modprobe vkms
udevadm settle
card="/dev/dri/$(ls /sys/devices/faux/vkms/drm/ | grep ^card)"
export WLR_BACKENDS=drm
export WLR_RENDERER=pixman
export WLR_DRM_DEVICES="$card"
export WLR_DRM_DEVICES=/dev/dri/by-path/platform-vkms-card
export UBSAN_OPTIONS=halt_on_error=1
sudo chmod ugo+rw "$card"
sudo chmod ugo+rw /dev/dri/by-path/platform-vkms-card
sudo -E seatd-launch -- ./tinywl -s 'kill $PPID' || [ $? = 143 ]

View file

@ -23,15 +23,16 @@ packages:
- x11-servers/xwayland
- sysutils/libdisplay-info
- sysutils/seatd
- gmake
- hwdata
sources:
- https://gitlab.freedesktop.org/wlroots/wlroots.git
tasks:
- wlroots: |
cd wlroots
meson setup build --fatal-meson-warnings -Dauto_features=enabled -Dallocators=gbm
meson setup build --fatal-meson-warnings -Dauto_features=enabled
ninja -C build
sudo ninja -C build install
- tinywl: |
cd wlroots/tinywl
make
gmake

3
.gitignore vendored
View file

@ -1,2 +1 @@
/subprojects/*
!/subprojects/*.wrap
/subprojects/

View file

@ -1,7 +1,6 @@
include: https://git.sr.ht/~emersion/dalligi/blob/master/templates/multi.yml
alpine:
extends: .dalligi
pages: true
archlinux:
extends: .dalligi
freebsd:

View file

@ -1,2 +1 @@
Isaac Freund <mail@isaacfreund.com> <ifreund@ifreund.xyz>
Kirill Primak <vyivel@eclair.cafe> <vyivel@posteo.net>

View file

@ -213,27 +213,6 @@ reinitialized to be used again.
it, and free the memory. Such functions should always be able to accept a NULL
pointer.
If the object has signals, the destructor function must assert that their
listener lists are empty.
```c
void wlr_thing_init(struct wlr_thing *thing) {
*thing = (struct wlr_thing){
// ...
};
wl_signal_init(&thing->events.destroy);
wl_signal_init(&thing->events.foo);
}
void wlr_thing_finish(struct wlr_thing *thing) {
wl_signal_emit_mutable(&thing->events.destroy, NULL);
assert(wl_list_empty(&thing->events.destroy.listener_list));
assert(wl_list_empty(&thing->events.foo.listener_list));
}
```
### Error Codes
For functions not returning a value, they should return a (stdbool.h) bool to
@ -258,13 +237,6 @@ used and `#undef` them after.
* Document the contents and container of a `struct wl_list` with a
`// content.link` and `// container.list` comment.
### Private fields
Wrap private fields of public structures with `struct { … } WLR_PRIVATE`. This
ensures that compositor authors don't use them by accident. Within wlroots
`WLR_PRIVATE` is expanded to nothing, so private fields are accessed in the same
way as public ones.
### Safety
* Avoid string manipulation functions which don't take the size of the
@ -353,14 +325,12 @@ struct wlr_compositor {
struct wl_global *global;
struct wl_listener display_destroy;
struct {
struct wl_signal new_surface;
struct wl_signal destroy;
} events;
struct {
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
```

View file

@ -1,4 +1,5 @@
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@ -11,6 +12,9 @@
#include <wlr/config.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/util/log.h>
#include "backend/backend.h"
#include "backend/multi.h"
#include "render/allocator/allocator.h"
#include "types/wlr_output.h"
#include "util/env.h"
#include "util/time.h"
@ -46,10 +50,6 @@ void wlr_backend_init(struct wlr_backend *backend,
void wlr_backend_finish(struct wlr_backend *backend) {
wl_signal_emit_mutable(&backend->events.destroy, backend);
assert(wl_list_empty(&backend->events.destroy.listener_list));
assert(wl_list_empty(&backend->events.new_input.listener_list));
assert(wl_list_empty(&backend->events.new_output.listener_list));
}
bool wlr_backend_start(struct wlr_backend *backend) {
@ -121,6 +121,14 @@ int wlr_backend_get_drm_fd(struct wlr_backend *backend) {
return backend->impl->get_drm_fd(backend);
}
uint32_t backend_get_buffer_caps(struct wlr_backend *backend) {
if (!backend->impl->get_buffer_caps) {
return 0;
}
return backend->impl->get_buffer_caps(backend);
}
static size_t parse_outputs_env(const char *name) {
const char *outputs_str = getenv(name);
if (outputs_str == NULL) {
@ -485,10 +493,5 @@ bool wlr_backend_commit(struct wlr_backend *backend,
output_apply_commit(state->output, &state->base);
}
for (size_t i = 0; i < states_len; i++) {
const struct wlr_backend_output_state *state = &states[i];
output_send_commit_event(state->output, &state->base);
}
return true;
}

View file

@ -1,16 +1,13 @@
#include <drm_fourcc.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <wlr/render/drm_syncobj.h>
#include <wlr/util/box.h>
#include <wlr/util/log.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include "backend/drm/drm.h"
#include "backend/drm/fb.h"
#include "backend/drm/iface.h"
#include "backend/drm/util.h"
#include "render/color.h"
static char *atomic_commit_flags_str(uint32_t flags) {
const char *const l[] = {
@ -155,20 +152,18 @@ static bool create_gamma_lut_blob(struct wlr_drm_backend *drm,
bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm,
int width, int height, const pixman_region32_t *damage, uint32_t *blob_id) {
if (!pixman_region32_not_empty(damage)) {
*blob_id = 0;
return true;
}
pixman_region32_t clipped;
pixman_region32_init(&clipped);
pixman_region32_intersect_rect(&clipped, damage, 0, 0, width, height);
int rects_len;
const pixman_box32_t *rects = pixman_region32_rectangles(&clipped, &rects_len);
int ret;
if (rects_len > 0) {
ret = drmModeCreatePropertyBlob(drm->fd, rects, sizeof(*rects) * rects_len, blob_id);
} else {
ret = 0;
*blob_id = 0;
}
int ret = drmModeCreatePropertyBlob(drm->fd, rects, sizeof(*rects) * rects_len, blob_id);
pixman_region32_fini(&clipped);
if (ret != 0) {
wlr_log_errno(WLR_ERROR, "Failed to create FB_DAMAGE_CLIPS property blob");
@ -178,85 +173,6 @@ bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm,
return true;
}
static uint8_t convert_cta861_eotf(enum wlr_color_transfer_function tf) {
switch (tf) {
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
abort(); // unsupported
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
return 2;
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
abort(); // unsupported
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
abort(); // unsupported
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
abort(); // unsupported
}
abort(); // unreachable
}
static uint16_t convert_cta861_color_coord(double v) {
if (v < 0) {
v = 0;
}
if (v > 1) {
v = 1;
}
return (uint16_t)round(v * 50000);
}
static bool create_hdr_output_metadata_blob(struct wlr_drm_backend *drm,
const struct wlr_output_image_description *img_desc, uint32_t *blob_id) {
if (img_desc == NULL) {
*blob_id = 0;
return true;
}
struct hdr_output_metadata metadata = {
.metadata_type = 0,
.hdmi_metadata_type1 = {
.eotf = convert_cta861_eotf(img_desc->transfer_function),
.metadata_type = 0,
.display_primaries = {
{
.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.red.x),
.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.red.y),
},
{
.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.green.x),
.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.green.y),
},
{
.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.blue.x),
.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.blue.y),
},
},
.white_point = {
.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.white.x),
.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.white.y),
},
.max_display_mastering_luminance = img_desc->mastering_luminance.max,
.min_display_mastering_luminance = img_desc->mastering_luminance.min * 0.0001,
.max_cll = img_desc->max_cll,
.max_fall = img_desc->max_fall,
},
};
if (drmModeCreatePropertyBlob(drm->fd, &metadata, sizeof(metadata), blob_id) != 0) {
wlr_log_errno(WLR_ERROR, "Failed to create HDR_OUTPUT_METADATA property");
return false;
}
return true;
}
static uint64_t convert_primaries_to_colorspace(uint32_t primaries) {
switch (primaries) {
case 0:
return 0; // Default
case WLR_COLOR_NAMED_PRIMARIES_BT2020:
return 9; // BT2020_RGB
}
abort(); // unreachable
}
static uint64_t max_bpc_for_format(uint32_t format) {
switch (format) {
case DRM_FORMAT_XRGB2101010:
@ -331,25 +247,19 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
}
uint32_t gamma_lut = crtc->gamma_lut;
if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
size_t dim = 0;
uint16_t *lut = NULL;
if (state->base->color_transform != NULL) {
struct wlr_color_transform_lut_3x1d *tr =
color_transform_lut_3x1d_from_base(state->base->color_transform);
dim = tr->dim;
lut = tr->lut_3x1d;
}
if (state->base->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
// Fallback to legacy gamma interface when gamma properties are not
// available (can happen on older Intel GPUs that support gamma but not
// degamma).
if (crtc->props.gamma_lut == 0) {
if (!drm_legacy_crtc_set_gamma(drm, crtc, dim, lut)) {
if (!drm_legacy_crtc_set_gamma(drm, crtc,
state->base->gamma_lut_size,
state->base->gamma_lut)) {
return false;
}
} else {
if (!create_gamma_lut_blob(drm, dim, lut, &gamma_lut)) {
if (!create_gamma_lut_blob(drm, state->base->gamma_lut_size,
state->base->gamma_lut, &gamma_lut)) {
return false;
}
}
@ -362,15 +272,6 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
state->primary_fb->wlr_buf->height, &state->base->damage, &fb_damage_clips);
}
int in_fence_fd = -1;
if (state->wait_timeline != NULL) {
in_fence_fd = wlr_drm_syncobj_timeline_export_sync_file(state->wait_timeline,
state->wait_point);
if (in_fence_fd < 0) {
return false;
}
}
bool prev_vrr_enabled =
output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
bool vrr_enabled = prev_vrr_enabled;
@ -381,25 +282,10 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
vrr_enabled = state->base->adaptive_sync_enabled;
}
uint32_t colorspace = conn->colorspace;
if (state->base->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
colorspace = convert_primaries_to_colorspace(
state->base->image_description ? state->base->image_description->primaries : 0);
}
uint32_t hdr_output_metadata = conn->hdr_output_metadata;
if ((state->base->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) &&
!create_hdr_output_metadata_blob(drm, state->base->image_description, &hdr_output_metadata)) {
return false;
}
state->mode_id = mode_id;
state->gamma_lut = gamma_lut;
state->fb_damage_clips = fb_damage_clips;
state->primary_in_fence_fd = in_fence_fd;
state->vrr_enabled = vrr_enabled;
state->colorspace = colorspace;
state->hdr_output_metadata = hdr_output_metadata;
return true;
}
@ -414,23 +300,11 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) {
crtc->own_mode_id = true;
commit_blob(drm, &crtc->mode_id, state->mode_id);
commit_blob(drm, &crtc->gamma_lut, state->gamma_lut);
commit_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
conn->output.adaptive_sync_status = state->vrr_enabled ?
WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED : WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED;
destroy_blob(drm, state->fb_damage_clips);
if (state->primary_in_fence_fd >= 0) {
close(state->primary_in_fence_fd);
}
if (state->out_fence_fd >= 0) {
// TODO: error handling
wlr_drm_syncobj_timeline_import_sync_file(state->base->signal_timeline,
state->base->signal_point, state->out_fence_fd);
close(state->out_fence_fd);
}
conn->colorspace = state->colorspace;
}
void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state) {
@ -440,15 +314,8 @@ void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state)
rollback_blob(drm, &crtc->mode_id, state->mode_id);
rollback_blob(drm, &crtc->gamma_lut, state->gamma_lut);
rollback_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
destroy_blob(drm, state->fb_damage_clips);
if (state->primary_in_fence_fd >= 0) {
close(state->primary_in_fence_fd);
}
if (state->out_fence_fd >= 0) {
close(state->out_fence_fd);
}
}
static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) {
@ -460,8 +327,7 @@ static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) {
static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm,
struct wlr_drm_plane *plane, struct wlr_drm_fb *fb, uint32_t crtc_id,
const struct wlr_box *dst_box,
const struct wlr_fbox *src_box) {
int32_t x, int32_t y) {
uint32_t id = plane->id;
const struct wlr_drm_plane_props *props = &plane->props;
@ -471,50 +337,28 @@ static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm,
return;
}
uint32_t width = fb->wlr_buf->width;
uint32_t height = fb->wlr_buf->height;
// The src_* properties are in 16.16 fixed point
atomic_add(atom, id, props->src_x, src_box->x * (1 << 16));
atomic_add(atom, id, props->src_y, src_box->y * (1 << 16));
atomic_add(atom, id, props->src_w, src_box->width * (1 << 16));
atomic_add(atom, id, props->src_h, src_box->height * (1 << 16));
atomic_add(atom, id, props->src_x, 0);
atomic_add(atom, id, props->src_y, 0);
atomic_add(atom, id, props->src_w, (uint64_t)width << 16);
atomic_add(atom, id, props->src_h, (uint64_t)height << 16);
atomic_add(atom, id, props->crtc_w, width);
atomic_add(atom, id, props->crtc_h, height);
atomic_add(atom, id, props->fb_id, fb->id);
atomic_add(atom, id, props->crtc_id, crtc_id);
atomic_add(atom, id, props->crtc_x, dst_box->x);
atomic_add(atom, id, props->crtc_y, dst_box->y);
atomic_add(atom, id, props->crtc_w, dst_box->width);
atomic_add(atom, id, props->crtc_h, dst_box->height);
atomic_add(atom, id, props->crtc_x, (uint64_t)x);
atomic_add(atom, id, props->crtc_y, (uint64_t)y);
}
static bool supports_cursor_hotspots(const struct wlr_drm_plane *plane) {
static bool supports_cursor_hotspots(const struct wlr_drm_plane* plane) {
return plane->props.hotspot_x && plane->props.hotspot_y;
}
static void set_plane_in_fence_fd(struct atomic *atom,
struct wlr_drm_plane *plane, int sync_file_fd) {
if (!plane->props.in_fence_fd) {
wlr_log(WLR_ERROR, "Plane %"PRIu32 " is missing the IN_FENCE_FD property",
plane->id);
atom->failed = true;
return;
}
atomic_add(atom, plane->id, plane->props.in_fence_fd, sync_file_fd);
}
static void set_crtc_out_fence_ptr(struct atomic *atom, struct wlr_drm_crtc *crtc,
int *fd_ptr) {
if (!crtc->props.out_fence_ptr) {
wlr_log(WLR_ERROR,
"CRTC %"PRIu32" is missing the OUT_FENCE_PTR property",
crtc->id);
atom->failed = true;
return;
}
atomic_add(atom, crtc->id, crtc->props.out_fence_ptr, (uintptr_t)fd_ptr);
}
static void atomic_connector_add(struct atomic *atom,
struct wlr_drm_connector_state *state, bool modeset) {
const struct wlr_drm_connector_state *state, bool modeset) {
struct wlr_drm_connector *conn = state->connector;
struct wlr_drm_backend *drm = conn->backend;
struct wlr_drm_crtc *crtc = conn->crtc;
@ -532,12 +376,6 @@ static void atomic_connector_add(struct atomic *atom,
if (modeset && active && conn->props.max_bpc != 0 && conn->max_bpc_bounds[1] != 0) {
atomic_add(atom, conn->id, conn->props.max_bpc, pick_max_bpc(conn, state->primary_fb));
}
if (conn->props.colorspace != 0) {
atomic_add(atom, conn->id, conn->props.colorspace, state->colorspace);
}
if (conn->props.hdr_output_metadata != 0) {
atomic_add(atom, conn->id, conn->props.hdr_output_metadata, state->hdr_output_metadata);
}
atomic_add(atom, crtc->id, crtc->props.mode_id, state->mode_id);
atomic_add(atom, crtc->id, crtc->props.active, active);
if (active) {
@ -547,33 +385,16 @@ static void atomic_connector_add(struct atomic *atom,
if (crtc->props.vrr_enabled != 0) {
atomic_add(atom, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled);
}
set_plane_props(atom, drm, crtc->primary, state->primary_fb, crtc->id,
&state->primary_viewport.dst_box, &state->primary_viewport.src_box);
0, 0);
if (crtc->primary->props.fb_damage_clips != 0) {
atomic_add(atom, crtc->primary->id,
crtc->primary->props.fb_damage_clips, state->fb_damage_clips);
}
if (state->primary_in_fence_fd >= 0) {
set_plane_in_fence_fd(atom, crtc->primary, state->primary_in_fence_fd);
}
if (state->base->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
set_crtc_out_fence_ptr(atom, crtc, &state->out_fence_fd);
}
if (crtc->cursor) {
if (drm_connector_is_cursor_visible(conn)) {
struct wlr_fbox cursor_src = {
.width = state->cursor_fb->wlr_buf->width,
.height = state->cursor_fb->wlr_buf->height,
};
struct wlr_box cursor_dst = {
.x = conn->cursor_x,
.y = conn->cursor_y,
.width = state->cursor_fb->wlr_buf->width,
.height = state->cursor_fb->wlr_buf->height,
};
set_plane_props(atom, drm, crtc->cursor, state->cursor_fb,
crtc->id, &cursor_dst, &cursor_src);
crtc->id, conn->cursor_x, conn->cursor_y);
if (supports_cursor_hotspots(crtc->cursor)) {
atomic_add(atom, crtc->cursor->id,
crtc->cursor->props.hotspot_x, conn->cursor_hotspot_x);
@ -616,7 +437,7 @@ static bool atomic_device_commit(struct wlr_drm_backend *drm,
if (state->modeset) {
flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
}
if (state->nonblock) {
if (!test_only && state->nonblock) {
flags |= DRM_MODE_ATOMIC_NONBLOCK;
}
@ -635,6 +456,33 @@ out:
return ok;
}
bool drm_atomic_reset(struct wlr_drm_backend *drm) {
struct atomic atom;
atomic_begin(&atom);
for (size_t i = 0; i < drm->num_crtcs; i++) {
struct wlr_drm_crtc *crtc = &drm->crtcs[i];
atomic_add(&atom, crtc->id, crtc->props.mode_id, 0);
atomic_add(&atom, crtc->id, crtc->props.active, 0);
}
struct wlr_drm_connector *conn;
wl_list_for_each(conn, &drm->connectors, link) {
atomic_add(&atom, conn->id, conn->props.crtc_id, 0);
}
for (size_t i = 0; i < drm->num_planes; i++) {
plane_disable(&atom, &drm->planes[i]);
}
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
bool ok = atomic_commit(&atom, drm, NULL, NULL, flags);
atomic_finish(&atom);
return ok;
}
const struct wlr_drm_interface atomic_iface = {
.commit = atomic_device_commit,
.reset = drm_atomic_reset,
};

View file

@ -1,8 +1,10 @@
#include <assert.h>
#include <errno.h>
#include <drm_fourcc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wayland-server-core.h>
#include <wlr/backend/interface.h>
#include <wlr/backend/session.h>
@ -11,7 +13,6 @@
#include <xf86drm.h>
#include "backend/drm/drm.h"
#include "backend/drm/fb.h"
#include "render/drm_format_set.h"
struct wlr_drm_backend *get_drm_backend_from_backend(
struct wlr_backend *wlr_backend) {
@ -52,8 +53,7 @@ static void backend_destroy(struct wlr_backend *backend) {
wl_list_remove(&drm->dev_change.link);
wl_list_remove(&drm->dev_remove.link);
if (drm->mgpu_renderer.wlr_rend) {
wlr_drm_format_set_finish(&drm->mgpu_formats);
if (drm->parent) {
finish_drm_renderer(&drm->mgpu_renderer);
}
@ -75,6 +75,10 @@ static int backend_get_drm_fd(struct wlr_backend *backend) {
return drm->fd;
}
static uint32_t backend_get_buffer_caps(struct wlr_backend *backend) {
return WLR_BUFFER_CAP_DMABUF;
}
static bool backend_test(struct wlr_backend *backend,
const struct wlr_backend_output_state *states, size_t states_len) {
struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend);
@ -91,6 +95,7 @@ static const struct wlr_backend_impl backend_impl = {
.start = backend_start,
.destroy = backend_destroy,
.get_drm_fd = backend_get_drm_fd,
.get_buffer_caps = backend_get_buffer_caps,
.test = backend_test,
.commit = backend_commit,
};
@ -112,18 +117,11 @@ static void handle_session_active(struct wl_listener *listener, void *data) {
wlr_log(WLR_INFO, "DRM FD %s", session->active ? "resumed" : "paused");
if (!session->active) {
// Disconnect any active connectors so that the client will modeset and
// rerender when the session is activated again.
struct wlr_drm_connector *conn;
wl_list_for_each(conn, &drm->connectors, link) {
if (conn->status == DRM_MODE_CONNECTED) {
wlr_output_destroy(&conn->output);
}
}
return;
}
scan_drm_connectors(drm, NULL);
restore_drm_device(drm);
}
static void handle_dev_change(struct wl_listener *listener, void *data) {
@ -167,44 +165,6 @@ static void handle_parent_destroy(struct wl_listener *listener, void *data) {
backend_destroy(&drm->backend);
}
static void sanitize_mgpu_modifiers(struct wlr_drm_format_set *set) {
for (size_t idx = 0; idx < set->len; idx++) {
// Implicit modifiers are not well-defined across devices, so strip
// them from all formats in multi-gpu scenarios.
struct wlr_drm_format *fmt = &set->formats[idx];
wlr_drm_format_set_remove(set, fmt->format, DRM_FORMAT_MOD_INVALID);
}
}
static bool init_mgpu_renderer(struct wlr_drm_backend *drm) {
if (!init_drm_renderer(drm, &drm->mgpu_renderer)) {
wlr_log(WLR_INFO, "Failed to initialize mgpu blit renderer"
", falling back to scanning out from primary GPU");
for (uint32_t plane_idx = 0; plane_idx < drm->num_planes; plane_idx++) {
struct wlr_drm_plane *plane = &drm->planes[plane_idx];
sanitize_mgpu_modifiers(&plane->formats);
}
return true;
}
// We'll perform a multi-GPU copy for all submitted buffers, we need
// to be able to texture from them
struct wlr_renderer *renderer = drm->mgpu_renderer.wlr_rend;
const struct wlr_drm_format_set *texture_formats =
wlr_renderer_get_texture_formats(renderer, WLR_BUFFER_CAP_DMABUF);
if (texture_formats == NULL) {
wlr_log(WLR_ERROR, "Failed to query renderer texture formats");
return false;
}
wlr_drm_format_set_copy(&drm->mgpu_formats, texture_formats);
sanitize_mgpu_modifiers(&drm->mgpu_formats);
drm->backend.features.timeline = drm->backend.features.timeline &&
drm->mgpu_renderer.wlr_rend->features.timeline;
return true;
}
struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
struct wlr_device *dev, struct wlr_backend *parent) {
assert(session && dev);
@ -232,8 +192,6 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
}
wlr_backend_init(&drm->backend, &backend_impl);
drm->backend.buffer_caps = WLR_BUFFER_CAP_DMABUF;
drm->session = session;
wl_list_init(&drm->fbs);
wl_list_init(&drm->connectors);
@ -276,8 +234,34 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
goto error_event;
}
if (drm->parent && !init_mgpu_renderer(drm)) {
goto error_mgpu_renderer;
if (drm->parent) {
if (!init_drm_renderer(drm, &drm->mgpu_renderer)) {
wlr_log(WLR_ERROR, "Failed to initialize renderer");
goto error_resources;
}
// We'll perform a multi-GPU copy for all submitted buffers, we need
// to be able to texture from them
struct wlr_renderer *renderer = drm->mgpu_renderer.wlr_rend;
const struct wlr_drm_format_set *texture_formats =
wlr_renderer_get_texture_formats(renderer, WLR_BUFFER_CAP_DMABUF);
if (texture_formats == NULL) {
wlr_log(WLR_ERROR, "Failed to query renderer texture formats");
goto error_mgpu_renderer;
}
// Forbid implicit modifiers, because their meaning changes from one
// GPU to another.
for (size_t i = 0; i < texture_formats->len; i++) {
const struct wlr_drm_format *fmt = &texture_formats->formats[i];
for (size_t j = 0; j < fmt->len; j++) {
uint64_t mod = fmt->modifiers[j];
if (mod == DRM_FORMAT_MOD_INVALID) {
continue;
}
wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format, mod);
}
}
}
drm->session_destroy.notify = handle_session_destroy;
@ -287,6 +271,7 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
error_mgpu_renderer:
finish_drm_renderer(&drm->mgpu_renderer);
error_resources:
finish_drm_resources(drm);
error_event:
wl_list_remove(&drm->session_active.link);

View file

@ -1,6 +1,7 @@
#include <assert.h>
#include <drm_fourcc.h>
#include <drm_mode.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdint.h>
@ -13,7 +14,6 @@
#include <wayland-util.h>
#include <wlr/backend/interface.h>
#include <wlr/interfaces/wlr_output.h>
#include <wlr/render/drm_syncobj.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/util/box.h>
#include <wlr/util/log.h>
@ -24,7 +24,9 @@
#include "backend/drm/fb.h"
#include "backend/drm/iface.h"
#include "backend/drm/util.h"
#include "render/color.h"
#include "render/pixel_format.h"
#include "render/drm_format_set.h"
#include "render/wlr_renderer.h"
#include "types/wlr_output.h"
#include "util/env.h"
#include "config.h"
@ -38,12 +40,9 @@ static const uint32_t COMMIT_OUTPUT_STATE =
WLR_OUTPUT_STATE_BUFFER |
WLR_OUTPUT_STATE_MODE |
WLR_OUTPUT_STATE_ENABLED |
WLR_OUTPUT_STATE_GAMMA_LUT |
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED |
WLR_OUTPUT_STATE_LAYERS |
WLR_OUTPUT_STATE_WAIT_TIMELINE |
WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
WLR_OUTPUT_STATE_COLOR_TRANSFORM |
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION;
WLR_OUTPUT_STATE_LAYERS;
static const uint32_t SUPPORTED_OUTPUT_STATE =
WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE;
@ -122,7 +121,6 @@ bool check_drm_features(struct wlr_drm_backend *drm) {
drm->supports_tearing_page_flips = drmGetCap(drm->fd, DRM_CAP_ASYNC_PAGE_FLIP, &cap) == 0 && cap == 1;
} else {
drm->supports_tearing_page_flips = drmGetCap(drm->fd, DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP, &cap) == 0 && cap == 1;
drm->backend.features.timeline = drmGetCap(drm->fd, DRM_CAP_SYNCOBJ_TIMELINE, &cap) == 0 && cap == 1;
}
if (env_parse_bool("WLR_DRM_NO_MODIFIERS")) {
@ -172,7 +170,7 @@ static bool init_plane(struct wlr_drm_backend *drm,
}
p->type = type;
p->id = id;
p->id = drm_plane->plane_id;
p->props = props;
p->initial_crtc_id = drm_plane->crtc_id;
@ -556,7 +554,6 @@ static void drm_connector_apply_commit(const struct wlr_drm_connector_state *sta
struct wlr_drm_crtc *crtc = conn->crtc;
drm_fb_copy(&crtc->primary->queued_fb, state->primary_fb);
crtc->primary->viewport = state->primary_viewport;
if (crtc->cursor != NULL) {
drm_fb_copy(&crtc->cursor->queued_fb, state->cursor_fb);
}
@ -580,16 +577,6 @@ static void drm_connector_apply_commit(const struct wlr_drm_connector_state *sta
conn->cursor_enabled = false;
conn->crtc = NULL;
// Legacy uAPI doesn't support requesting page-flip events when
// turning off a CRTC
if (page_flip != NULL && conn->backend->iface == &legacy_iface) {
drm_page_flip_pop(page_flip, crtc->id);
conn->pending_page_flip = NULL;
if (page_flip->connectors_len == 0) {
drm_page_flip_destroy(page_flip);
}
}
}
}
@ -645,8 +632,6 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
.connector = conn,
.base = base,
.active = output_pending_enabled(&conn->output, base),
.primary_in_fence_fd = -1,
.out_fence_fd = -1,
};
struct wlr_output_mode *mode = conn->output.current_mode;
@ -656,7 +641,7 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
if (base->committed & WLR_OUTPUT_STATE_MODE) {
switch (base->mode_type) {
case WLR_OUTPUT_STATE_MODE_FIXED:
case WLR_OUTPUT_STATE_MODE_FIXED:;
mode = base->mode;
break;
case WLR_OUTPUT_STATE_MODE_CUSTOM:
@ -683,10 +668,8 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
struct wlr_drm_plane *primary = conn->crtc->primary;
if (primary->queued_fb != NULL) {
state->primary_fb = drm_fb_lock(primary->queued_fb);
state->primary_viewport = primary->viewport;
} else if (primary->current_fb != NULL) {
state->primary_fb = drm_fb_lock(primary->current_fb);
state->primary_viewport = primary->viewport;
}
if (conn->cursor_enabled) {
@ -706,7 +689,6 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
static void drm_connector_state_finish(struct wlr_drm_connector_state *state) {
drm_fb_clear(&state->primary_fb);
drm_fb_clear(&state->cursor_fb);
wlr_drm_syncobj_timeline_unref(state->wait_timeline);
}
static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn,
@ -721,16 +703,8 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn
struct wlr_drm_plane *plane = crtc->primary;
struct wlr_buffer *source_buf = state->base->buffer;
struct wlr_drm_syncobj_timeline *wait_timeline = NULL;
uint64_t wait_point = 0;
if (state->base->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
wait_timeline = state->base->wait_timeline;
wait_point = state->base->wait_point;
}
assert(state->wait_timeline == NULL);
struct wlr_buffer *local_buf;
if (drm->mgpu_renderer.wlr_rend) {
if (drm->parent) {
struct wlr_drm_format format = {0};
if (!drm_plane_pick_render_format(plane, &format, &drm->mgpu_renderer)) {
wlr_log(WLR_ERROR, "Failed to pick primary plane format");
@ -745,23 +719,12 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn
return false;
}
local_buf = drm_surface_blit(&plane->mgpu_surf, source_buf,
wait_timeline, wait_point);
local_buf = drm_surface_blit(&plane->mgpu_surf, source_buf);
if (local_buf == NULL) {
return false;
}
if (plane->mgpu_surf.timeline != NULL) {
state->wait_timeline = wlr_drm_syncobj_timeline_ref(plane->mgpu_surf.timeline);
state->wait_point = plane->mgpu_surf.point;
}
} else {
local_buf = wlr_buffer_lock(source_buf);
if (wait_timeline != NULL) {
state->wait_timeline = wlr_drm_syncobj_timeline_ref(wait_timeline);
state->wait_point = wait_point;
}
}
bool ok = drm_fb_import(&state->primary_fb, drm, local_buf,
@ -773,9 +736,6 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn
return false;
}
output_state_get_buffer_src_box(state->base, &state->primary_viewport.src_box);
output_state_get_buffer_dst_box(state->base, &state->primary_viewport.dst_box);
return true;
}
@ -784,7 +744,7 @@ static bool drm_connector_set_pending_layer_fbs(struct wlr_drm_connector *conn,
struct wlr_drm_backend *drm = conn->backend;
struct wlr_drm_crtc *crtc = conn->crtc;
if (!crtc || drm->mgpu_renderer.wlr_rend) {
if (!crtc || drm->parent) {
return false;
}
@ -826,12 +786,13 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo
return false;
}
if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled &&
output->width == 0 && output->height == 0 &&
!(state->committed & WLR_OUTPUT_STATE_MODE)) {
wlr_drm_conn_log(conn, WLR_DEBUG,
"Can't enable an output without a mode");
return false;
if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled) {
if (output->current_mode == NULL &&
!(state->committed & WLR_OUTPUT_STATE_MODE)) {
wlr_drm_conn_log(conn, WLR_DEBUG,
"Can't enable an output without a mode");
return false;
}
}
if ((state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) &&
@ -842,36 +803,7 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo
return false;
}
if ((state->committed & WLR_OUTPUT_STATE_BUFFER) && conn->backend->mgpu_renderer.wlr_rend) {
struct wlr_dmabuf_attributes dmabuf;
if (!wlr_buffer_get_dmabuf(state->buffer, &dmabuf)) {
wlr_drm_conn_log(conn, WLR_DEBUG, "Buffer is not a DMA-BUF");
return false;
}
if (!wlr_drm_format_set_has(&conn->backend->mgpu_formats, dmabuf.format, dmabuf.modifier)) {
wlr_drm_conn_log(conn, WLR_DEBUG,
"Buffer format 0x%"PRIX32" with modifier 0x%"PRIX64" cannot be "
"imported into multi-GPU renderer",
dmabuf.format, dmabuf.modifier);
return false;
}
}
if ((state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) && state->color_transform != NULL &&
state->color_transform->type != COLOR_TRANSFORM_LUT_3X1D) {
wlr_drm_conn_log(conn, WLR_DEBUG,
"Only 3x1D LUT color transforms are supported");
return false;
}
if ((state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) &&
conn->backend->iface != &atomic_iface) {
wlr_log(WLR_DEBUG, "Image descriptions are only supported by the atomic interface");
return false;
}
if (test_only && conn->backend->mgpu_renderer.wlr_rend) {
if (test_only && conn->backend->parent) {
// If we're running as a secondary GPU, we can't perform an atomic
// commit without blitting a buffer.
return true;
@ -941,7 +873,7 @@ static bool drm_connector_commit_state(struct wlr_drm_connector *conn,
goto out;
}
if (test_only && conn->backend->mgpu_renderer.wlr_rend) {
if (test_only && conn->backend->parent) {
// If we're running as a secondary GPU, we can't perform an atomic
// commit without blitting a buffer.
ok = true;
@ -1138,7 +1070,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
}
struct wlr_buffer *local_buf;
if (drm->mgpu_renderer.wlr_rend) {
if (drm->parent) {
struct wlr_drm_format format = {0};
if (!drm_plane_pick_render_format(plane, &format, &drm->mgpu_renderer)) {
wlr_log(WLR_ERROR, "Failed to pick cursor plane format");
@ -1152,7 +1084,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
return false;
}
local_buf = drm_surface_blit(&plane->mgpu_surf, buffer, NULL, 0);
local_buf = drm_surface_blit(&plane->mgpu_surf, buffer);
if (local_buf == NULL) {
return false;
}
@ -1172,6 +1104,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
conn->cursor_height = buffer->height;
}
wlr_output_update_needs_frame(output);
return true;
}
@ -1201,6 +1134,7 @@ static bool drm_connector_move_cursor(struct wlr_output *output,
conn->cursor_x = box.x;
conn->cursor_y = box.y;
wlr_output_update_needs_frame(output);
return true;
}
@ -1223,8 +1157,6 @@ static void dealloc_crtc(struct wlr_drm_connector *conn);
static void drm_connector_destroy_output(struct wlr_output *output) {
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
wlr_output_finish(output);
dealloc_crtc(conn);
conn->status = DRM_MODE_DISCONNECTED;
@ -1252,7 +1184,7 @@ static const struct wlr_drm_format_set *drm_connector_get_cursor_formats(
if (!plane) {
return NULL;
}
if (conn->backend->mgpu_renderer.wlr_rend) {
if (conn->backend->parent) {
return &conn->backend->mgpu_formats;
}
return &plane->formats;
@ -1281,7 +1213,7 @@ static const struct wlr_drm_format_set *drm_connector_get_primary_formats(
if (!drm_connector_alloc_crtc(conn)) {
return NULL;
}
if (conn->backend->mgpu_renderer.wlr_rend) {
if (conn->backend->parent) {
return &conn->backend->mgpu_formats;
}
return &conn->crtc->primary->formats;
@ -1418,7 +1350,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm,
++i;
}
match_connectors_with_crtcs(num_connectors, connector_constraints,
match_obj(num_connectors, connector_constraints,
drm->num_crtcs, previous_match, new_match);
// Converts our crtc=>connector result into a connector=>crtc one.
@ -1546,14 +1478,14 @@ static struct wlr_drm_connector *create_drm_connector(struct wlr_drm_backend *dr
return NULL;
}
const char *conn_type_name =
const char *conn_name =
drmModeGetConnectorTypeName(drm_conn->connector_type);
if (conn_type_name == NULL) {
conn_type_name = "Unknown";
if (conn_name == NULL) {
conn_name = "Unknown";
}
snprintf(wlr_conn->name, sizeof(wlr_conn->name),
"%s-%"PRIu32, conn_type_name, drm_conn->connector_type_id);
"%s-%"PRIu32, conn_name, drm_conn->connector_type_id);
wlr_conn->possible_crtcs =
drmModeConnectorGetPossibleCrtcs(drm->fd, drm_conn);
@ -1624,7 +1556,6 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
wlr_log(WLR_INFO, "Detected modes:");
bool found_current_mode = false;
for (int i = 0; i < drm_conn->count_modes; ++i) {
if (drm_conn->modes[i].flags & DRM_MODE_FLAG_INTERLACE) {
continue;
@ -1643,7 +1574,14 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
if (current_modeinfo != NULL && memcmp(&mode->drm_mode,
current_modeinfo, sizeof(*current_modeinfo)) == 0) {
wlr_output_state_set_mode(&state, &mode->wlr_mode);
found_current_mode = true;
uint64_t mode_id = 0;
get_drm_prop(drm->fd, wlr_conn->crtc->id,
wlr_conn->crtc->props.mode_id, &mode_id);
wlr_conn->crtc->own_mode_id = false;
wlr_conn->crtc->mode_id = mode_id;
wlr_conn->refresh = calculate_refresh_rate(current_modeinfo);
}
wlr_log(WLR_INFO, " %"PRId32"x%"PRId32" @ %.3f Hz %s",
@ -1654,23 +1592,6 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
wl_list_insert(modes.prev, &mode->wlr_mode.link);
}
if (current_modeinfo != NULL) {
int32_t refresh = calculate_refresh_rate(current_modeinfo);
if (!found_current_mode) {
wlr_output_state_set_custom_mode(&state,
current_modeinfo->hdisplay, current_modeinfo->vdisplay, refresh);
}
uint64_t mode_id = 0;
get_drm_prop(drm->fd, wlr_conn->crtc->id,
wlr_conn->crtc->props.mode_id, &mode_id);
wlr_conn->crtc->own_mode_id = false;
wlr_conn->crtc->mode_id = mode_id;
wlr_conn->refresh = refresh;
}
free(current_modeinfo);
wlr_output_init(output, &drm->backend, &output_impl, drm->session->event_loop, &state);
@ -1717,11 +1638,7 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
size_t edid_len = 0;
uint8_t *edid = get_drm_prop_blob(drm->fd,
wlr_conn->id, wlr_conn->props.edid, &edid_len);
if (edid_len > 0) {
parse_edid(wlr_conn, edid_len, edid);
} else {
wlr_log(WLR_DEBUG, "Connector has no EDID");
}
parse_edid(wlr_conn, edid_len, edid);
free(edid);
char *subconnector = NULL;
@ -1787,10 +1704,6 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
}
}
if (wlr_conn && wlr_conn->lease) {
continue;
}
// If the hotplug event contains a connector ID, ignore any other
// connector.
if (event != NULL && event->connector_id != 0 &&
@ -1868,6 +1781,8 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
destroy_drm_connector(conn);
}
realloc_crtcs(drm, NULL);
for (size_t i = 0; i < new_outputs_len; ++i) {
struct wlr_drm_connector *conn = new_outputs[i];
@ -1907,6 +1822,108 @@ void scan_drm_leases(struct wlr_drm_backend *drm) {
drmFree(list);
}
static void build_current_connector_state(struct wlr_output_state *state,
struct wlr_drm_connector *conn) {
bool enabled = conn->status != DRM_MODE_DISCONNECTED && conn->output.enabled;
wlr_output_state_init(state);
wlr_output_state_set_enabled(state, enabled);
if (!enabled) {
return;
}
if (conn->output.current_mode != NULL) {
wlr_output_state_set_mode(state, conn->output.current_mode);
} else {
wlr_output_state_set_custom_mode(state,
conn->output.width, conn->output.height, conn->output.refresh);
}
}
/**
* Check whether we need to perform a full reset after a VT switch.
*
* If any connector or plane has a different CRTC, we need to perform a full
* reset to restore our mapping. We couldn't avoid a full reset even if we
* used a single KMS atomic commit to apply our state: the kernel rejects
* commits which migrate a plane from one CRTC to another without going through
* an intermediate state where the plane is disabled.
*/
static bool skip_reset_for_restore(struct wlr_drm_backend *drm) {
struct wlr_drm_connector *conn;
wl_list_for_each(conn, &drm->connectors, link) {
drmModeConnector *drm_conn = drmModeGetConnectorCurrent(drm->fd, conn->id);
if (drm_conn == NULL) {
return false;
}
struct wlr_drm_crtc *crtc = connector_get_current_crtc(conn, drm_conn);
drmModeFreeConnector(drm_conn);
if (crtc != NULL && conn->crtc != crtc) {
return false;
}
}
for (size_t i = 0; i < drm->num_planes; i++) {
struct wlr_drm_plane *plane = &drm->planes[i];
drmModePlane *drm_plane = drmModeGetPlane(drm->fd, plane->id);
if (drm_plane == NULL) {
return false;
}
uint32_t crtc_id = drm_plane->crtc_id;
drmModeFreePlane(drm_plane);
struct wlr_drm_crtc *crtc = NULL;
for (size_t i = 0; i < drm->num_crtcs; i++) {
if (drm->crtcs[i].id == crtc_id) {
crtc = &drm->crtcs[i];
break;
}
}
if (crtc == NULL) {
continue;
}
bool ok = false;
switch (plane->type) {
case DRM_PLANE_TYPE_PRIMARY:
ok = crtc->primary == plane;
break;
case DRM_PLANE_TYPE_CURSOR:
ok = crtc->cursor == plane;
break;
}
if (!ok) {
return false;
}
}
return true;
}
void restore_drm_device(struct wlr_drm_backend *drm) {
// The previous DRM master leaves KMS in an undefined state. We need
// to restore our own state, but be careful to avoid invalid
// configurations. The connector/CRTC mapping may have changed, so
// first disable all CRTCs, then light up the ones we were using
// before the VT switch.
// TODO: better use the atomic API to improve restoration after a VT switch
if (!skip_reset_for_restore(drm) && !drm->iface->reset(drm)) {
wlr_log(WLR_ERROR, "Failed to reset state after VT switch");
}
struct wlr_drm_connector *conn;
wl_list_for_each(conn, &drm->connectors, link) {
struct wlr_output_state state;
build_current_connector_state(&state, conn);
if (!drm_connector_commit_state(conn, &state, false)) {
wlr_drm_conn_log(conn, WLR_ERROR, "Failed to restore state after VT switch");
}
wlr_output_state_finish(&state);
}
}
bool commit_drm_device(struct wlr_drm_backend *drm,
const struct wlr_backend_output_state *output_states, size_t output_states_len,
bool test_only) {
@ -1955,7 +1972,7 @@ bool commit_drm_device(struct wlr_drm_backend *drm,
modeset |= output_state->base.allow_reconfiguration;
}
if (test_only && drm->mgpu_renderer.wlr_rend) {
if (test_only && drm->parent) {
// If we're running as a secondary GPU, we can't perform an atomic
// commit without blitting a buffer.
ok = true;
@ -2033,19 +2050,20 @@ static void handle_page_flip(int fd, unsigned seq,
* data between the GPUs, even if we were using the direct scanout
* interface.
*/
if (!drm->mgpu_renderer.wlr_rend) {
if (!drm->parent) {
present_flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
}
struct timespec present_time = {
.tv_sec = tv_sec,
.tv_nsec = tv_usec * 1000,
};
struct wlr_output_event_present present_event = {
/* The DRM backend guarantees that the presentation event will be for
* the last submitted frame. */
.commit_seq = conn->output.commit_seq,
.presented = drm->session->active,
.when = {
.tv_sec = tv_sec,
.tv_nsec = tv_usec * 1000,
},
.when = &present_time,
.seq = seq,
.refresh = mhz_to_nsec(conn->refresh),
.flags = present_flags,
@ -2179,7 +2197,6 @@ struct wlr_drm_lease *wlr_drm_create_lease(struct wlr_output **outputs,
get_drm_connector_from_output(outputs[i]);
conn->lease = lease;
conn->crtc->lease = lease;
disconnect_drm_connector(conn);
}
return lease;
@ -2202,8 +2219,6 @@ void drm_lease_destroy(struct wlr_drm_lease *lease) {
wl_signal_emit_mutable(&lease->events.destroy, NULL);
assert(wl_list_empty(&lease->events.destroy.listener_list));
struct wlr_drm_connector *conn;
wl_list_for_each(conn, &drm->connectors, link) {
if (conn->lease == lease) {
@ -2218,5 +2233,4 @@ void drm_lease_destroy(struct wlr_drm_lease *lease) {
}
free(lease);
scan_drm_connectors(drm, NULL);
}

View file

@ -7,8 +7,6 @@
#include "backend/drm/fb.h"
#include "backend/drm/iface.h"
#include "backend/drm/util.h"
#include "render/color.h"
#include "types/wlr_output.h"
static bool legacy_fb_props_match(struct wlr_drm_fb *fb1,
struct wlr_drm_fb *fb2) {
@ -41,41 +39,20 @@ static bool legacy_crtc_test(const struct wlr_drm_connector_state *state,
struct wlr_drm_connector *conn = state->connector;
struct wlr_drm_crtc *crtc = conn->crtc;
if (state->base->committed & WLR_OUTPUT_STATE_BUFFER) {
// If the size doesn't match, reject buffer (scaling is not supported)
int pending_width, pending_height;
output_pending_resolution(&state->connector->output, state->base,
&pending_width, &pending_height);
if (state->base->buffer->width != pending_width ||
state->base->buffer->height != pending_height) {
wlr_log(WLR_DEBUG, "Primary buffer size mismatch");
return false;
}
// Source crop is also not supported
struct wlr_fbox src_box;
output_state_get_buffer_src_box(state->base, &src_box);
if (src_box.x != 0.0 || src_box.y != 0.0 ||
src_box.width != (double)state->base->buffer->width ||
src_box.height != (double)state->base->buffer->height) {
wlr_log(WLR_DEBUG, "Source crop not supported in DRM-legacy output");
return false;
if ((state->base->committed & WLR_OUTPUT_STATE_BUFFER) && !modeset) {
struct wlr_drm_fb *pending_fb = state->primary_fb;
struct wlr_drm_fb *prev_fb = crtc->primary->queued_fb;
if (!prev_fb) {
prev_fb = crtc->primary->current_fb;
}
if (!modeset) {
struct wlr_drm_fb *pending_fb = state->primary_fb;
struct wlr_drm_fb *prev_fb = crtc->primary->queued_fb;
if (!prev_fb) {
prev_fb = crtc->primary->current_fb;
}
/* Legacy is only guaranteed to be able to display a FB if it's been
* allocated the same way as the previous one. */
if (prev_fb != NULL && !legacy_fb_props_match(prev_fb, pending_fb)) {
wlr_drm_conn_log(conn, WLR_DEBUG,
"Cannot change scan-out buffer parameters with legacy KMS API");
return false;
}
/* Legacy is only guaranteed to be able to display a FB if it's been
* allocated the same way as the previous one. */
if (prev_fb != NULL && !legacy_fb_props_match(prev_fb, pending_fb)) {
wlr_drm_conn_log(conn, WLR_DEBUG,
"Cannot change scan-out buffer parameters with legacy KMS API");
return false;
}
}
@ -125,17 +102,9 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
}
}
if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
size_t dim = 0;
uint16_t *lut = NULL;
if (state->base->color_transform != NULL) {
struct wlr_color_transform_lut_3x1d *tr =
color_transform_lut_3x1d_from_base(state->base->color_transform);
dim = tr->dim;
lut = tr->lut_3x1d;
}
if (!drm_legacy_crtc_set_gamma(drm, crtc, dim, lut)) {
if (state->base->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
if (!drm_legacy_crtc_set_gamma(drm, crtc,
state->base->gamma_lut_size, state->base->gamma_lut)) {
return false;
}
}
@ -159,7 +128,7 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
state->base->adaptive_sync_enabled ? "enabled" : "disabled");
}
if (cursor != NULL && state->active && drm_connector_is_cursor_visible(conn)) {
if (cursor != NULL && drm_connector_is_cursor_visible(conn)) {
struct wlr_drm_fb *cursor_fb = state->cursor_fb;
if (cursor_fb == NULL) {
wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to acquire cursor FB");
@ -201,9 +170,7 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
}
}
// Legacy uAPI doesn't support requesting page-flip events when
// turning off a CRTC
if (state->active && (flags & DRM_MODE_PAGE_FLIP_EVENT)) {
if (flags & DRM_MODE_PAGE_FLIP_EVENT) {
if (drmModePageFlip(drm->fd, crtc->id, fb_id, flags, page_flip)) {
wlr_drm_conn_log_errno(conn, WLR_ERROR, "drmModePageFlip failed");
return false;
@ -281,6 +248,20 @@ bool drm_legacy_crtc_set_gamma(struct wlr_drm_backend *drm,
return true;
}
static bool legacy_reset(struct wlr_drm_backend *drm) {
bool ok = true;
for (size_t i = 0; i < drm->num_crtcs; i++) {
struct wlr_drm_crtc *crtc = &drm->crtcs[i];
if (drmModeSetCrtc(drm->fd, crtc->id, 0, 0, 0, NULL, 0, NULL) != 0) {
wlr_log_errno(WLR_ERROR, "Failed to disable CRTC %"PRIu32,
crtc->id);
ok = false;
}
}
return ok;
}
const struct wlr_drm_interface legacy_iface = {
.commit = legacy_commit,
.reset = legacy_reset,
};

View file

@ -4,14 +4,12 @@
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wlr/util/box.h>
#include <wlr/util/log.h>
#include "backend/drm/drm.h"
#include "backend/drm/fb.h"
#include "backend/drm/iface.h"
#include "config.h"
#include "types/wlr_output.h"
static void log_handler(enum liftoff_log_priority priority, const char *fmt, va_list args) {
enum wlr_log_importance importance = WLR_SILENT;
@ -151,23 +149,25 @@ static bool add_prop(drmModeAtomicReq *req, uint32_t obj,
}
static bool set_plane_props(struct wlr_drm_plane *plane,
struct liftoff_layer *layer, struct wlr_drm_fb *fb, uint64_t zpos,
const struct wlr_box *dst_box, const struct wlr_fbox *src_box) {
struct liftoff_layer *layer, struct wlr_drm_fb *fb, int32_t x, int32_t y, uint64_t zpos) {
if (fb == NULL) {
wlr_log(WLR_ERROR, "Failed to acquire FB for plane %"PRIu32, plane->id);
return false;
}
// The src_* properties are in 16.16 fixed point
uint32_t width = fb->wlr_buf->width;
uint32_t height = fb->wlr_buf->height;
// The SRC_* properties are in 16.16 fixed point
return liftoff_layer_set_property(layer, "zpos", zpos) == 0 &&
liftoff_layer_set_property(layer, "SRC_X", src_box->x * (1 << 16)) == 0 &&
liftoff_layer_set_property(layer, "SRC_Y", src_box->y * (1 << 16)) == 0 &&
liftoff_layer_set_property(layer, "SRC_W", src_box->width * (1 << 16)) == 0 &&
liftoff_layer_set_property(layer, "SRC_H", src_box->height * (1 << 16)) == 0 &&
liftoff_layer_set_property(layer, "CRTC_X", dst_box->x) == 0 &&
liftoff_layer_set_property(layer, "CRTC_Y", dst_box->y) == 0 &&
liftoff_layer_set_property(layer, "CRTC_W", dst_box->width) == 0 &&
liftoff_layer_set_property(layer, "CRTC_H", dst_box->height) == 0 &&
liftoff_layer_set_property(layer, "SRC_X", 0) == 0 &&
liftoff_layer_set_property(layer, "SRC_Y", 0) == 0 &&
liftoff_layer_set_property(layer, "SRC_W", (uint64_t)width << 16) == 0 &&
liftoff_layer_set_property(layer, "SRC_H", (uint64_t)height << 16) == 0 &&
liftoff_layer_set_property(layer, "CRTC_X", (uint64_t)x) == 0 &&
liftoff_layer_set_property(layer, "CRTC_Y", (uint64_t)y) == 0 &&
liftoff_layer_set_property(layer, "CRTC_W", width) == 0 &&
liftoff_layer_set_property(layer, "CRTC_H", height) == 0 &&
liftoff_layer_set_property(layer, "FB_ID", fb->id) == 0;
}
@ -331,32 +331,14 @@ static bool add_connector(drmModeAtomicReq *req,
if (crtc->props.vrr_enabled != 0) {
ok = ok && add_prop(req, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled);
}
ok = ok && set_plane_props(crtc->primary,
crtc->primary->liftoff_layer, state->primary_fb, 0,
&state->primary_viewport.dst_box,
&state->primary_viewport.src_box);
ok = ok && set_plane_props(crtc->primary,
crtc->liftoff_composition_layer, state->primary_fb, 0,
&state->primary_viewport.dst_box,
&state->primary_viewport.src_box);
ok = ok &&
set_plane_props(crtc->primary, crtc->primary->liftoff_layer, state->primary_fb, 0, 0, 0) &&
set_plane_props(crtc->primary, crtc->liftoff_composition_layer, state->primary_fb, 0, 0, 0);
liftoff_layer_set_property(crtc->primary->liftoff_layer,
"FB_DAMAGE_CLIPS", state->fb_damage_clips);
liftoff_layer_set_property(crtc->liftoff_composition_layer,
"FB_DAMAGE_CLIPS", state->fb_damage_clips);
if (state->primary_in_fence_fd >= 0) {
liftoff_layer_set_property(crtc->primary->liftoff_layer,
"IN_FENCE_FD", state->primary_in_fence_fd);
liftoff_layer_set_property(crtc->liftoff_composition_layer,
"IN_FENCE_FD", state->primary_in_fence_fd);
}
if (state->base->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
ok = ok && add_prop(req, crtc->id, crtc->props.out_fence_ptr,
(uintptr_t)&state->out_fence_fd);
}
if (state->base->committed & WLR_OUTPUT_STATE_LAYERS) {
for (size_t i = 0; i < state->base->layers_len; i++) {
const struct wlr_output_layer_state *layer_state = &state->base->layers[i];
@ -367,19 +349,9 @@ static bool add_connector(drmModeAtomicReq *req,
if (crtc->cursor) {
if (drm_connector_is_cursor_visible(conn)) {
struct wlr_fbox cursor_src = {
.width = state->cursor_fb->wlr_buf->width,
.height = state->cursor_fb->wlr_buf->height,
};
struct wlr_box cursor_dst = {
.x = conn->cursor_x,
.y = conn->cursor_y,
.width = state->cursor_fb->wlr_buf->width,
.height = state->cursor_fb->wlr_buf->height,
};
ok = ok && set_plane_props(crtc->cursor, crtc->cursor->liftoff_layer,
state->cursor_fb, wl_list_length(&crtc->layers) + 1,
&cursor_dst, &cursor_src);
state->cursor_fb, conn->cursor_x, conn->cursor_y,
wl_list_length(&crtc->layers) + 1);
} else {
ok = ok && disable_plane(crtc->cursor);
}
@ -425,7 +397,7 @@ static bool commit(struct wlr_drm_backend *drm,
if (state->modeset) {
flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
}
if (state->nonblock) {
if (!test_only && state->nonblock) {
flags |= DRM_MODE_ATOMIC_NONBLOCK;
}
@ -507,4 +479,5 @@ const struct wlr_drm_interface liftoff_iface = {
.init = init,
.finish = finish,
.commit = commit,
.reset = drm_atomic_reset,
};

View file

@ -7,7 +7,6 @@ hwdata = dependency(
libdisplay_info = dependency(
'libdisplay-info',
version: '>=0.2.0',
required: 'drm' in backends,
fallback: 'libdisplay-info',
not_found_message: 'Required for the DRM backend.',

View file

@ -3,7 +3,6 @@
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <inttypes.h>
#include <wlr/util/log.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
@ -22,10 +21,8 @@ struct prop_info {
static const struct prop_info connector_info[] = {
#define INDEX(name) (offsetof(struct wlr_drm_connector_props, name) / sizeof(uint32_t))
{ "CRTC_ID", INDEX(crtc_id) },
{ "Colorspace", INDEX(colorspace) },
{ "DPMS", INDEX(dpms) },
{ "EDID", INDEX(edid) },
{ "HDR_OUTPUT_METADATA", INDEX(hdr_output_metadata) },
{ "PATH", INDEX(path) },
{ "content type", INDEX(content_type) },
{ "link-status", INDEX(link_status) },
@ -43,7 +40,6 @@ static const struct prop_info crtc_info[] = {
{ "GAMMA_LUT", INDEX(gamma_lut) },
{ "GAMMA_LUT_SIZE", INDEX(gamma_lut_size) },
{ "MODE_ID", INDEX(mode_id) },
{ "OUT_FENCE_PTR", INDEX(out_fence_ptr) },
{ "VRR_ENABLED", INDEX(vrr_enabled) },
#undef INDEX
};
@ -59,7 +55,6 @@ static const struct prop_info plane_info[] = {
{ "FB_ID", INDEX(fb_id) },
{ "HOTSPOT_X", INDEX(hotspot_x) },
{ "HOTSPOT_Y", INDEX(hotspot_y) },
{ "IN_FENCE_FD", INDEX(in_fence_fd) },
{ "IN_FORMATS", INDEX(in_formats) },
{ "SIZE_HINTS", INDEX(size_hints) },
{ "SRC_H", INDEX(src_h) },
@ -82,14 +77,14 @@ static bool scan_properties(int fd, uint32_t id, uint32_t type, uint32_t *result
const struct prop_info *info, size_t info_len) {
drmModeObjectProperties *props = drmModeObjectGetProperties(fd, id, type);
if (!props) {
wlr_log_errno(WLR_ERROR, "Failed to get DRM object %" PRIu32 " properties", id);
wlr_log_errno(WLR_ERROR, "Failed to get DRM object properties");
return false;
}
for (uint32_t i = 0; i < props->count_props; ++i) {
drmModePropertyRes *prop = drmModeGetProperty(fd, props->props[i]);
if (!prop) {
wlr_log_errno(WLR_ERROR, "Failed to get property %" PRIu32 " of DRM object %" PRIu32, props->props[i], id);
wlr_log_errno(WLR_ERROR, "Failed to get DRM object property");
continue;
}

View file

@ -1,35 +1,31 @@
#include <assert.h>
#include <drm_fourcc.h>
#include <wlr/render/allocator.h>
#include <wlr/render/drm_syncobj.h>
#include <wlr/render/swapchain.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/util/log.h>
#include "backend/drm/drm.h"
#include "backend/drm/fb.h"
#include "backend/drm/renderer.h"
#include "backend/backend.h"
#include "render/drm_format_set.h"
#include "render/allocator/allocator.h"
#include "render/pixel_format.h"
#include "render/wlr_renderer.h"
bool init_drm_renderer(struct wlr_drm_backend *drm,
struct wlr_drm_renderer *renderer) {
wlr_log(WLR_DEBUG, "Creating multi-GPU renderer");
renderer->wlr_rend = renderer_autocreate_with_drm_fd(drm->fd);
if (!renderer->wlr_rend) {
return false;
}
if (wlr_renderer_get_texture_formats(renderer->wlr_rend, WLR_BUFFER_CAP_DMABUF) == NULL) {
wlr_log(WLR_ERROR, "Renderer did not support importing DMA-BUFs");
wlr_renderer_destroy(renderer->wlr_rend);
renderer->wlr_rend = NULL;
wlr_log(WLR_ERROR, "Failed to create renderer");
return false;
}
renderer->allocator = wlr_allocator_autocreate(&drm->backend, renderer->wlr_rend);
uint32_t backend_caps = backend_get_buffer_caps(&drm->backend);
renderer->allocator = allocator_autocreate_with_drm_fd(backend_caps,
renderer->wlr_rend, drm->fd);
if (renderer->allocator == NULL) {
wlr_log(WLR_ERROR, "Failed to create allocator");
wlr_renderer_destroy(renderer->wlr_rend);
renderer->wlr_rend = NULL;
return false;
}
@ -50,7 +46,6 @@ void finish_drm_surface(struct wlr_drm_surface *surf) {
return;
}
wlr_drm_syncobj_timeline_unref(surf->timeline);
wlr_swapchain_destroy(surf->swapchain);
*surf = (struct wlr_drm_surface){0};
@ -73,24 +68,13 @@ bool init_drm_surface(struct wlr_drm_surface *surf,
return false;
}
int drm_fd = wlr_renderer_get_drm_fd(renderer->wlr_rend);
if (renderer->wlr_rend->features.timeline && drm_fd >= 0) {
surf->timeline = wlr_drm_syncobj_timeline_create(drm_fd);
if (surf->timeline == NULL) {
finish_drm_surface(surf);
wlr_log(WLR_ERROR, "Failed to create DRM syncobj timeline");
return false;
}
}
surf->renderer = renderer;
return true;
}
struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
struct wlr_buffer *buffer,
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point) {
struct wlr_buffer *buffer) {
struct wlr_renderer *renderer = surf->renderer->wlr_rend;
if (surf->swapchain->width != buffer->width ||
@ -105,18 +89,13 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
return NULL;
}
struct wlr_buffer *dst = wlr_swapchain_acquire(surf->swapchain);
struct wlr_buffer *dst = wlr_swapchain_acquire(surf->swapchain, NULL);
if (!dst) {
wlr_log(WLR_ERROR, "Failed to acquire multi-GPU swapchain buffer");
goto error_tex;
}
surf->point++;
const struct wlr_buffer_pass_options pass_options = {
.signal_timeline = surf->timeline,
.signal_point = surf->point,
};
struct wlr_render_pass *pass = wlr_renderer_begin_buffer_pass(renderer, dst, &pass_options);
struct wlr_render_pass *pass = wlr_renderer_begin_buffer_pass(renderer, dst, NULL);
if (pass == NULL) {
wlr_log(WLR_ERROR, "Failed to begin render pass with multi-GPU destination buffer");
goto error_dst;
@ -125,8 +104,6 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
wlr_render_pass_add_texture(pass, &(struct wlr_render_texture_options){
.texture = tex,
.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
.wait_timeline = wait_timeline,
.wait_point = wait_point,
});
if (!wlr_render_pass_submit(pass)) {
wlr_log(WLR_ERROR, "Failed to submit multi-GPU render pass");

View file

@ -83,28 +83,6 @@ void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data)
output->model = di_info_get_model(info);
output->serial = di_info_get_serial(info);
const struct di_color_primaries *color_characteristics = di_info_get_default_color_primaries(info);
if (color_characteristics->has_primaries) {
output->default_primaries_value = (struct wlr_color_primaries) {
.red = { .x = color_characteristics->primary[0].x, .y = color_characteristics->primary[0].y },
.green = { .x = color_characteristics->primary[1].x, .y = color_characteristics->primary[1].y },
.blue = { .x = color_characteristics->primary[2].x, .y = color_characteristics->primary[2].y },
.white = { .x = color_characteristics->default_white.x, .y = color_characteristics->default_white.y },
};
output->default_primaries = &output->default_primaries_value;
}
const struct di_supported_signal_colorimetry *colorimetry = di_info_get_supported_signal_colorimetry(info);
bool has_bt2020 = colorimetry->bt2020_cycc || colorimetry->bt2020_ycc || colorimetry->bt2020_rgb;
if (conn->props.colorspace != 0 && has_bt2020) {
output->supported_primaries |= WLR_COLOR_NAMED_PRIMARIES_BT2020;
}
const struct di_hdr_static_metadata *hdr_static_metadata = di_info_get_hdr_static_metadata(info);
if (conn->props.hdr_output_metadata != 0 && hdr_static_metadata->type1 && hdr_static_metadata->pq) {
output->supported_transfer_functions |= WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
}
di_info_destroy(info);
}
@ -134,9 +112,9 @@ static bool is_taken(size_t n, const uint32_t arr[static n], uint32_t key) {
* passing 12 arguments to a function.
*/
struct match_state {
const size_t num_conns;
const uint32_t *restrict conns;
const size_t num_crtcs;
const size_t num_objs;
const uint32_t *restrict objs;
const size_t num_res;
size_t score;
size_t replaced;
uint32_t *restrict res;
@ -145,31 +123,27 @@ struct match_state {
bool exit_early;
};
/**
* Step to process a CRTC.
*
* This is a naive implementation of maximum bipartite matching.
*
* score: The number of connectors we've matched so far.
/*
* skips: The number of SKIP elements encountered so far.
* score: The number of resources we've matched so far.
* replaced: The number of changes from the original solution.
* crtc_index: The index of the current CRTC.
* i: The index of the current element.
*
* This tries to match a solution as close to st->orig as it can.
*
* Returns whether we've set a new best element with this solution.
*/
static bool match_connectors_with_crtcs_(struct match_state *st,
size_t score, size_t replaced, size_t crtc_index) {
static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_t replaced, size_t i) {
// Finished
if (crtc_index >= st->num_crtcs) {
if (i >= st->num_res) {
if (score > st->score ||
(score == st->score && replaced < st->replaced)) {
st->score = score;
st->replaced = replaced;
memcpy(st->best, st->res, sizeof(st->best[0]) * st->num_crtcs);
memcpy(st->best, st->res, sizeof(st->best[0]) * st->num_res);
st->exit_early = (st->score == st->num_crtcs
|| st->score == st->num_conns)
st->exit_early = (st->score == st->num_res - skips
|| st->score == st->num_objs)
&& st->replaced == 0;
return true;
@ -178,16 +152,21 @@ static bool match_connectors_with_crtcs_(struct match_state *st,
}
}
if (st->orig[i] == SKIP) {
st->res[i] = SKIP;
return match_obj_(st, skips + 1, score, replaced, i + 1);
}
bool has_best = false;
/*
* Attempt to use the current solution first, to try and avoid
* recalculating everything
*/
if (st->orig[crtc_index] != UNMATCHED && !is_taken(crtc_index, st->res, st->orig[crtc_index])) {
st->res[crtc_index] = st->orig[crtc_index];
size_t crtc_score = st->conns[st->res[crtc_index]] != 0 ? 1 : 0;
if (match_connectors_with_crtcs_(st, score + crtc_score, replaced, crtc_index + 1)) {
if (st->orig[i] != UNMATCHED && !is_taken(i, st->res, st->orig[i])) {
st->res[i] = st->orig[i];
size_t obj_score = st->objs[st->res[i]] != 0 ? 1 : 0;
if (match_obj_(st, skips, score + obj_score, replaced, i + 1)) {
has_best = true;
}
}
@ -195,29 +174,29 @@ static bool match_connectors_with_crtcs_(struct match_state *st,
return true;
}
if (st->orig[crtc_index] != UNMATCHED) {
if (st->orig[i] != UNMATCHED) {
++replaced;
}
for (size_t candidate = 0; candidate < st->num_conns; ++candidate) {
for (size_t candidate = 0; candidate < st->num_objs; ++candidate) {
// We tried this earlier
if (candidate == st->orig[crtc_index]) {
if (candidate == st->orig[i]) {
continue;
}
// Not compatible
if (!(st->conns[candidate] & (1 << crtc_index))) {
if (!(st->objs[candidate] & (1 << i))) {
continue;
}
// Already taken
if (is_taken(crtc_index, st->res, candidate)) {
if (is_taken(i, st->res, candidate)) {
continue;
}
st->res[crtc_index] = candidate;
size_t crtc_score = st->conns[candidate] != 0 ? 1 : 0;
if (match_connectors_with_crtcs_(st, score + crtc_score, replaced, crtc_index + 1)) {
st->res[i] = candidate;
size_t obj_score = st->objs[candidate] != 0 ? 1 : 0;
if (match_obj_(st, skips, score + obj_score, replaced, i + 1)) {
has_best = true;
}
@ -226,37 +205,37 @@ static bool match_connectors_with_crtcs_(struct match_state *st,
}
}
// Maybe this CRTC can't be matched
st->res[crtc_index] = UNMATCHED;
if (match_connectors_with_crtcs_(st, score, replaced, crtc_index + 1)) {
// Maybe this resource can't be matched
st->res[i] = UNMATCHED;
if (match_obj_(st, skips, score, replaced, i + 1)) {
has_best = true;
}
return has_best;
}
void match_connectors_with_crtcs(size_t num_conns,
const uint32_t conns[static restrict num_conns],
size_t num_crtcs, const uint32_t prev_crtcs[static restrict num_crtcs],
uint32_t new_crtcs[static restrict num_crtcs]) {
uint32_t solution[num_crtcs];
for (size_t i = 0; i < num_crtcs; ++i) {
size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs],
size_t num_res, const uint32_t res[static restrict num_res],
uint32_t out[static restrict num_res]) {
uint32_t solution[num_res];
for (size_t i = 0; i < num_res; ++i) {
solution[i] = UNMATCHED;
}
struct match_state st = {
.num_conns = num_conns,
.num_crtcs = num_crtcs,
.num_objs = num_objs,
.num_res = num_res,
.score = 0,
.replaced = SIZE_MAX,
.conns = conns,
.objs = objs,
.res = solution,
.best = new_crtcs,
.orig = prev_crtcs,
.best = out,
.orig = res,
.exit_early = false,
};
match_connectors_with_crtcs_(&st, 0, 0, 0);
match_obj_(&st, 0, 0, 0, 0);
return st.score;
}
void generate_cvt_mode(drmModeModeInfo *mode, int hdisplay, int vdisplay,

View file

@ -45,9 +45,16 @@ static void backend_destroy(struct wlr_backend *wlr_backend) {
free(backend);
}
static uint32_t get_buffer_caps(struct wlr_backend *wlr_backend) {
return WLR_BUFFER_CAP_DATA_PTR
| WLR_BUFFER_CAP_DMABUF
| WLR_BUFFER_CAP_SHM;
}
static const struct wlr_backend_impl backend_impl = {
.start = backend_start,
.destroy = backend_destroy,
.get_buffer_caps = get_buffer_caps,
};
static void handle_event_loop_destroy(struct wl_listener *listener, void *data) {
@ -67,17 +74,12 @@ struct wlr_backend *wlr_headless_backend_create(struct wl_event_loop *loop) {
wlr_backend_init(&backend->backend, &backend_impl);
backend->backend.buffer_caps =
WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_DMABUF | WLR_BUFFER_CAP_SHM;
backend->event_loop = loop;
wl_list_init(&backend->outputs);
backend->event_loop_destroy.notify = handle_event_loop_destroy;
wl_event_loop_add_destroy_listener(loop, &backend->event_loop_destroy);
backend->backend.features.timeline = true;
return &backend->backend;
}

View file

@ -79,20 +79,9 @@ static bool output_commit(struct wlr_output *wlr_output,
return true;
}
static bool output_set_cursor(struct wlr_output *wlr_output,
struct wlr_buffer *buffer, int hotspot_x, int hotspot_y) {
return true;
}
static bool output_move_cursor(struct wlr_output *wlr_output, int x, int y) {
return true;
}
static void output_destroy(struct wlr_output *wlr_output) {
struct wlr_headless_output *output = headless_output_from_output(wlr_output);
wlr_output_finish(wlr_output);
struct wlr_headless_output *output =
headless_output_from_output(wlr_output);
wl_list_remove(&output->link);
wl_event_source_remove(output->frame_timer);
free(output);
@ -100,10 +89,7 @@ static void output_destroy(struct wlr_output *wlr_output) {
static const struct wlr_output_impl output_impl = {
.destroy = output_destroy,
.test = output_test,
.commit = output_commit,
.set_cursor = output_set_cursor,
.move_cursor = output_move_cursor,
};
bool wlr_output_is_headless(struct wlr_output *wlr_output) {

View file

@ -61,15 +61,25 @@ void handle_pointer_button(struct libinput_event *event,
.time_msec = usec_to_msec(libinput_event_pointer_get_time_usec(pevent)),
.button = libinput_event_pointer_get_button(pevent),
};
// Ignore events which aren't a seat-wide state change. For instance, if
// the same button is pressed twice on the same seat, ignore the second
// press.
uint32_t seat_count = libinput_event_pointer_get_seat_button_count(pevent);
switch (libinput_event_pointer_get_button_state(pevent)) {
case LIBINPUT_BUTTON_STATE_PRESSED:
wlr_event.state = WL_POINTER_BUTTON_STATE_PRESSED;
if (seat_count != 1) {
return;
}
break;
case LIBINPUT_BUTTON_STATE_RELEASED:
wlr_event.state = WL_POINTER_BUTTON_STATE_RELEASED;
if (seat_count != 0) {
return;
}
break;
}
wlr_pointer_notify_button(pointer, &wlr_event);
wl_signal_emit_mutable(&pointer->events.button, &wlr_event);
wl_signal_emit_mutable(&pointer->events.frame, pointer);
}

View file

@ -104,7 +104,6 @@ void init_device_tablet_pad(struct wlr_libinput_input_device *dev) {
struct udev_device *udev = libinput_device_get_udev_device(handle);
char **dst = wl_array_add(&wlr_tablet_pad->paths, sizeof(char *));
*dst = strdup(udev_device_get_syspath(udev));
udev_device_unref(udev);
int groups = libinput_device_tablet_pad_get_num_mode_groups(handle);
for (int i = 0; i < groups; ++i) {

View file

@ -6,7 +6,6 @@
#include <wlr/interfaces/wlr_tablet_tool.h>
#include <wlr/util/log.h>
#include "backend/libinput.h"
#include "config.h"
struct tablet_tool {
struct wlr_tablet_tool wlr_tool;
@ -37,7 +36,6 @@ void init_device_tablet(struct wlr_libinput_input_device *dev) {
struct udev_device *udev = libinput_device_get_udev_device(dev->handle);
char **dst = wl_array_add(&wlr_tablet->paths, sizeof(char *));
*dst = strdup(udev_device_get_syspath(udev));
udev_device_unref(udev);
wl_list_init(&dev->tablet_tools);
}

View file

@ -6,6 +6,7 @@
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_output.h>
#include <wlr/util/log.h>
#include "backend/backend.h"
#include "backend/multi.h"
struct subbackend_state {
@ -51,9 +52,6 @@ static void multi_backend_destroy(struct wlr_backend *wlr_backend) {
wlr_backend_finish(wlr_backend);
assert(wl_list_empty(&backend->events.backend_add.listener_list));
assert(wl_list_empty(&backend->events.backend_remove.listener_list));
// Some backends may depend on other backends, ie. destroying a backend may
// also destroy other backends
while (!wl_list_empty(&backend->backends)) {
@ -78,6 +76,28 @@ static int multi_backend_get_drm_fd(struct wlr_backend *backend) {
return -1;
}
static uint32_t multi_backend_get_buffer_caps(struct wlr_backend *backend) {
struct wlr_multi_backend *multi = multi_backend_from_backend(backend);
if (wl_list_empty(&multi->backends)) {
return 0;
}
uint32_t caps = WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_DMABUF
| WLR_BUFFER_CAP_SHM;
struct subbackend_state *sub;
wl_list_for_each(sub, &multi->backends, link) {
uint32_t backend_caps = backend_get_buffer_caps(sub->backend);
if (backend_caps != 0) {
// only count backend capable of presenting a buffer
caps = caps & backend_caps;
}
}
return caps;
}
static int compare_output_state_backend(const void *data_a, const void *data_b) {
const struct wlr_backend_output_state *a = data_a;
const struct wlr_backend_output_state *b = data_b;
@ -106,24 +126,22 @@ static bool commit(struct wlr_backend *backend,
qsort(by_backend, states_len, sizeof(by_backend[0]), compare_output_state_backend);
bool ok = true;
for (size_t i = 0; i < states_len;) {
for (size_t i = 0; i < states_len; i++) {
struct wlr_backend *sub = by_backend[i].output->backend;
size_t len = 1;
while (i + len < states_len &&
by_backend[i + len].output->backend == sub) {
len++;
size_t j = i;
while (j < states_len && by_backend[j].output->backend == sub) {
j++;
}
if (test_only) {
ok = wlr_backend_test(sub, &by_backend[i], len);
ok = wlr_backend_test(sub, &by_backend[i], j - i);
} else {
ok = wlr_backend_commit(sub, &by_backend[i], len);
ok = wlr_backend_commit(sub, &by_backend[i], j - i);
}
if (!ok) {
break;
}
i += len;
}
free(by_backend);
@ -144,6 +162,7 @@ static const struct wlr_backend_impl backend_impl = {
.start = multi_backend_start,
.destroy = multi_backend_destroy,
.get_drm_fd = multi_backend_get_drm_fd,
.get_buffer_caps = multi_backend_get_buffer_caps,
.test = multi_backend_test,
.commit = multi_backend_commit,
};
@ -206,33 +225,6 @@ static struct subbackend_state *multi_backend_get_subbackend(struct wlr_multi_ba
return NULL;
}
static void multi_backend_refresh_features(struct wlr_multi_backend *multi) {
multi->backend.buffer_caps = 0;
multi->backend.features.timeline = true;
bool has_buffer_cap = false;
uint32_t buffer_caps_intersection =
WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_DMABUF | WLR_BUFFER_CAP_SHM;
struct subbackend_state *sub = NULL;
wl_list_for_each(sub, &multi->backends, link) {
// Only take into account backends capable of presenting a buffer
if (sub->backend->buffer_caps != 0) {
has_buffer_cap = true;
buffer_caps_intersection &= sub->backend->buffer_caps;
}
// timeline is only applicable to backends that support DMABUFs
if (sub->backend->buffer_caps & WLR_BUFFER_CAP_DMABUF) {
multi->backend.features.timeline = multi->backend.features.timeline &&
sub->backend->features.timeline;
}
}
if (has_buffer_cap) {
multi->backend.buffer_caps = buffer_caps_intersection;
}
}
bool wlr_multi_backend_add(struct wlr_backend *_multi,
struct wlr_backend *backend) {
assert(_multi && backend);
@ -264,7 +256,6 @@ bool wlr_multi_backend_add(struct wlr_backend *_multi,
wl_signal_add(&backend->events.new_output, &sub->new_output);
sub->new_output.notify = new_output_reemit;
multi_backend_refresh_features(multi);
wl_signal_emit_mutable(&multi->events.backend_add, backend);
return true;
}
@ -279,7 +270,6 @@ void wlr_multi_backend_remove(struct wlr_backend *_multi,
if (sub) {
wl_signal_emit_mutable(&multi->events.backend_remove, backend);
subbackend_state_destroy(sub);
multi_backend_refresh_features(multi);
}
}

View file

@ -191,40 +191,32 @@ static int handle_udev_event(int fd, uint32_t mask, void *data) {
goto out;
}
dev_t devnum = udev_device_get_devnum(udev_dev);
if (strcmp(action, "add") == 0) {
struct wlr_device *dev;
wl_list_for_each(dev, &session->devices, link) {
if (dev->dev == devnum) {
wlr_log(WLR_DEBUG, "Skipping duplicate device %s", sysname);
goto out;
}
}
wlr_log(WLR_DEBUG, "DRM device %s added", sysname);
struct wlr_session_add_event event = {
.path = devnode,
};
wl_signal_emit_mutable(&session->events.add_drm_card, &event);
} else if (strcmp(action, "change") == 0) {
} else if (strcmp(action, "change") == 0 || strcmp(action, "remove") == 0) {
dev_t devnum = udev_device_get_devnum(udev_dev);
struct wlr_device *dev;
wl_list_for_each(dev, &session->devices, link) {
if (dev->dev == devnum) {
if (dev->dev != devnum) {
continue;
}
if (strcmp(action, "change") == 0) {
wlr_log(WLR_DEBUG, "DRM device %s changed", sysname);
struct wlr_device_change_event event = {0};
read_udev_change_event(&event, udev_dev);
wl_signal_emit_mutable(&dev->events.change, &event);
break;
}
}
} else if (strcmp(action, "remove") == 0) {
struct wlr_device *dev;
wl_list_for_each(dev, &session->devices, link) {
if (dev->dev == devnum) {
} else if (strcmp(action, "remove") == 0) {
wlr_log(WLR_DEBUG, "DRM device %s removed", sysname);
wl_signal_emit_mutable(&dev->events.remove, NULL);
break;
} else {
assert(0);
}
break;
}
}
@ -303,11 +295,6 @@ void wlr_session_destroy(struct wlr_session *session) {
}
wl_signal_emit_mutable(&session->events.destroy, session);
assert(wl_list_empty(&session->events.active.listener_list));
assert(wl_list_empty(&session->events.add_drm_card.listener_list));
assert(wl_list_empty(&session->events.destroy.listener_list));
wl_list_remove(&session->event_loop_destroy.link);
wl_event_source_remove(session->udev_event);
@ -365,13 +352,6 @@ void wlr_session_close_file(struct wlr_session *session,
if (libseat_close_device(session->seat_handle, dev->device_id) == -1) {
wlr_log_errno(WLR_ERROR, "Failed to close device %d", dev->device_id);
}
assert(wl_list_empty(&dev->events.change.listener_list));
// TODO: assert that the "remove" listener list is empty as well. Listeners
// will typically call wlr_session_close_file() in response, and
// wl_signal_emit_mutable() installs two phantom listeners, so we'd count
// these two.
close(dev->fd);
wl_list_remove(&dev->link);
free(dev);
@ -519,6 +499,8 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
break;
}
bool is_boot_vga = false;
const char *path = udev_list_entry_get_name(entry);
struct udev_device *dev = udev_device_new_from_syspath(session->udev, path);
if (!dev) {
@ -534,20 +516,14 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
continue;
}
bool is_primary = false;
const char *boot_display = udev_device_get_sysattr_value(dev, "boot_display");
if (boot_display && strcmp(boot_display, "1") == 0) {
is_primary = true;
} else {
// This is owned by 'dev', so we don't need to free it
struct udev_device *pci =
udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
// This is owned by 'dev', so we don't need to free it
struct udev_device *pci =
udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
if (pci) {
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
if (id && strcmp(id, "1") == 0) {
is_primary = true;
}
if (pci) {
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
if (id && strcmp(id, "1") == 0) {
is_boot_vga = true;
}
}
@ -561,7 +537,7 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
udev_device_unref(dev);
ret[i] = wlr_dev;
if (is_primary) {
if (is_boot_vga) {
struct wlr_device *tmp = ret[0];
ret[0] = ret[i];
ret[i] = tmp;

View file

@ -21,7 +21,6 @@
#include "drm-client-protocol.h"
#include "linux-dmabuf-v1-client-protocol.h"
#include "linux-drm-syncobj-v1-client-protocol.h"
#include "pointer-gestures-unstable-v1-client-protocol.h"
#include "presentation-time-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
@ -55,6 +54,14 @@ struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *wlr_backe
static int dispatch_events(int fd, uint32_t mask, void *data) {
struct wlr_wl_backend *wl = data;
if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
if (mask & WL_EVENT_ERROR) {
wlr_log(WLR_ERROR, "Failed to read from remote Wayland display");
}
wlr_backend_destroy(&wl->backend);
return 0;
}
int count = 0;
if (mask & WL_EVENT_READABLE) {
count = wl_display_dispatch(wl->remote_display);
@ -67,18 +74,6 @@ static int dispatch_events(int fd, uint32_t mask, void *data) {
wl_display_flush(wl->remote_display);
}
// Make sure we've consumed all data before disconnecting due to hangup,
// so that we process any wl_display.error events
if (!(mask & WL_EVENT_READABLE) && (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR))) {
if (mask & WL_EVENT_ERROR) {
wlr_log(WLR_ERROR, "Failed to read from remote Wayland display");
} else {
wlr_log(WLR_DEBUG, "Disconnected from remote Wayland display");
}
wlr_backend_destroy(&wl->backend);
return 0;
}
if (count < 0) {
wlr_log(WLR_ERROR, "Failed to dispatch remote Wayland display");
wlr_backend_destroy(&wl->backend);
@ -416,9 +411,6 @@ static void registry_global(void *data, struct wl_registry *registry,
} else if (strcmp(iface, wp_viewporter_interface.name) == 0) {
wl->viewporter = wl_registry_bind(registry, name,
&wp_viewporter_interface, 1);
} else if (strcmp(iface, wp_linux_drm_syncobj_manager_v1_interface.name) == 0) {
wl->drm_syncobj_manager_v1 = wl_registry_bind(registry, name,
&wp_linux_drm_syncobj_manager_v1_interface, 1);
}
}
@ -492,11 +484,6 @@ static void backend_destroy(struct wlr_backend *backend) {
destroy_wl_buffer(buffer);
}
struct wlr_wl_drm_syncobj_timeline *timeline, *tmp_timeline;
wl_list_for_each_safe(timeline, tmp_timeline, &wl->drm_syncobj_timelines, link) {
destroy_wl_drm_syncobj_timeline(timeline);
}
wlr_backend_finish(backend);
wl_list_remove(&wl->event_loop_destroy.link);
@ -531,9 +518,6 @@ static void backend_destroy(struct wlr_backend *backend) {
if (wl->zwp_linux_dmabuf_v1) {
zwp_linux_dmabuf_v1_destroy(wl->zwp_linux_dmabuf_v1);
}
if (wl->drm_syncobj_manager_v1) {
wp_linux_drm_syncobj_manager_v1_destroy(wl->drm_syncobj_manager_v1);
}
if (wl->legacy_drm != NULL) {
wl_drm_destroy(wl->legacy_drm);
}
@ -559,7 +543,6 @@ static void backend_destroy(struct wlr_backend *backend) {
wl_compositor_destroy(wl->compositor);
wl_registry_destroy(wl->registry);
wl_display_flush(wl->remote_display);
wl_event_queue_destroy(wl->busy_loop_queue);
if (wl->own_remote_display) {
wl_display_disconnect(wl->remote_display);
}
@ -571,10 +554,17 @@ static int backend_get_drm_fd(struct wlr_backend *backend) {
return wl->drm_fd;
}
static uint32_t get_buffer_caps(struct wlr_backend *backend) {
struct wlr_wl_backend *wl = get_wl_backend_from_backend(backend);
return (wl->zwp_linux_dmabuf_v1 ? WLR_BUFFER_CAP_DMABUF : 0)
| (wl->shm ? WLR_BUFFER_CAP_SHM : 0);
}
static const struct wlr_backend_impl backend_impl = {
.start = backend_start,
.destroy = backend_destroy,
.get_drm_fd = backend_get_drm_fd,
.get_buffer_caps = get_buffer_caps,
};
bool wlr_backend_is_wl(struct wlr_backend *b) {
@ -602,7 +592,6 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop,
wl_list_init(&wl->outputs);
wl_list_init(&wl->seats);
wl_list_init(&wl->buffers);
wl_list_init(&wl->drm_syncobj_timelines);
if (remote_display != NULL) {
wl->remote_display = remote_display;
@ -615,16 +604,10 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop,
wl->own_remote_display = true;
}
wl->busy_loop_queue = wl_display_create_queue(wl->remote_display);
if (wl->busy_loop_queue == NULL) {
wlr_log_errno(WLR_ERROR, "Could not create a Wayland event queue");
goto error_display;
}
wl->registry = wl_display_get_registry(wl->remote_display);
if (!wl->registry) {
wlr_log_errno(WLR_ERROR, "Could not obtain reference to remote registry");
goto error_queue;
goto error_display;
}
wl_registry_add_listener(wl->registry, &registry_listener, wl);
@ -641,8 +624,6 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop,
goto error_registry;
}
wl->backend.features.timeline = wl->drm_syncobj_manager_v1 != NULL;
wl_display_roundtrip(wl->remote_display); // process initial event bursts
struct zwp_linux_dmabuf_feedback_v1 *linux_dmabuf_feedback_v1 = NULL;
@ -676,13 +657,6 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop,
zwp_linux_dmabuf_feedback_v1_destroy(linux_dmabuf_feedback_v1);
}
if (wl->zwp_linux_dmabuf_v1) {
wl->backend.buffer_caps |= WLR_BUFFER_CAP_DMABUF;
}
if (wl->shm) {
wl->backend.buffer_caps |= WLR_BUFFER_CAP_SHM;
}
int fd = wl_display_get_fd(wl->remote_display);
wl->remote_display_src = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
dispatch_events, wl);
@ -726,8 +700,6 @@ error_registry:
xdg_wm_base_destroy(wl->xdg_wm_base);
}
wl_registry_destroy(wl->registry);
error_queue:
wl_event_queue_destroy(wl->busy_loop_queue);
error_display:
if (wl->own_remote_display) {
wl_display_disconnect(wl->remote_display);

View file

@ -1,5 +1,6 @@
wayland_client = dependency('wayland-client',
kwargs: wayland_kwargs,
fallback: 'wayland',
default_options: wayland_project_options,
)
wlr_deps += wayland_client
@ -14,7 +15,6 @@ wlr_files += files(
client_protos = [
'drm',
'linux-dmabuf-v1',
'linux-drm-syncobj-v1',
'pointer-gestures-unstable-v1',
'presentation-time',
'relative-pointer-unstable-v1',

View file

@ -11,7 +11,6 @@
#include <wayland-client-protocol.h>
#include <wlr/interfaces/wlr_output.h>
#include <wlr/render/drm_syncobj.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_output_layer.h>
#include <wlr/util/log.h>
@ -21,7 +20,6 @@
#include "types/wlr_output.h"
#include "linux-dmabuf-v1-client-protocol.h"
#include "linux-drm-syncobj-v1-client-protocol.h"
#include "presentation-time-client-protocol.h"
#include "viewporter-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
@ -33,9 +31,7 @@ static const uint32_t SUPPORTED_OUTPUT_STATE =
WLR_OUTPUT_STATE_BUFFER |
WLR_OUTPUT_STATE_ENABLED |
WLR_OUTPUT_STATE_MODE |
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED |
WLR_OUTPUT_STATE_WAIT_TIMELINE |
WLR_OUTPUT_STATE_SIGNAL_TIMELINE;
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED;
static size_t last_output_num = 0;
@ -98,13 +94,14 @@ static void presentation_feedback_handle_presented(void *data,
uint32_t seq_hi, uint32_t seq_lo, uint32_t flags) {
struct wlr_wl_presentation_feedback *feedback = data;
struct timespec t = {
.tv_sec = ((uint64_t)tv_sec_hi << 32) | tv_sec_lo,
.tv_nsec = tv_nsec,
};
struct wlr_output_event_present event = {
.commit_seq = feedback->commit_seq,
.presented = true,
.when = {
.tv_sec = ((uint64_t)tv_sec_hi << 32) | tv_sec_lo,
.tv_nsec = tv_nsec,
},
.when = &t,
.seq = ((uint64_t)seq_hi << 32) | seq_lo,
.refresh = refresh_ns,
.flags = flags,
@ -134,11 +131,6 @@ static const struct wp_presentation_feedback_listener
.discarded = presentation_feedback_handle_discarded,
};
static void buffer_remove_drm_syncobj_waiter(struct wlr_wl_buffer *buffer) {
wlr_drm_syncobj_timeline_waiter_finish(&buffer->drm_syncobj_waiter);
buffer->has_drm_syncobj_waiter = false;
}
void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
if (buffer == NULL) {
return;
@ -146,42 +138,22 @@ void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
wl_list_remove(&buffer->buffer_destroy.link);
wl_list_remove(&buffer->link);
wl_buffer_destroy(buffer->wl_buffer);
if (buffer->has_drm_syncobj_waiter) {
buffer_remove_drm_syncobj_waiter(buffer);
}
if (!buffer->released) {
wlr_buffer_unlock(buffer->buffer);
}
wlr_drm_syncobj_timeline_unref(buffer->fallback_signal_timeline);
free(buffer);
}
static void buffer_release(struct wlr_wl_buffer *buffer) {
if (buffer->released) {
return;
}
buffer->released = true;
wlr_buffer_unlock(buffer->buffer); // might free buffer
}
static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) {
struct wlr_wl_buffer *buffer = data;
if (buffer->has_drm_syncobj_waiter) {
return;
}
buffer_release(buffer);
buffer->released = true;
wlr_buffer_unlock(buffer->buffer); // might free buffer
}
static const struct wl_buffer_listener buffer_listener = {
.release = buffer_handle_release,
};
static void buffer_handle_drm_syncobj_ready(struct wlr_drm_syncobj_timeline_waiter *waiter) {
struct wlr_wl_buffer *buffer = wl_container_of(waiter, buffer, drm_syncobj_waiter);
buffer_remove_drm_syncobj_waiter(buffer);
buffer_release(buffer);
}
static void buffer_handle_buffer_destroy(struct wl_listener *listener,
void *data) {
struct wlr_wl_buffer *buffer =
@ -204,30 +176,6 @@ static bool test_buffer(struct wlr_wl_backend *wl,
}
}
struct dmabuf_listener_data {
struct wl_buffer *wl_buffer;
bool done;
};
static void dmabuf_handle_created(void *data_, struct zwp_linux_buffer_params_v1 *params,
struct wl_buffer *buffer) {
struct dmabuf_listener_data *data = data_;
data->wl_buffer = buffer;
data->done = true;
wlr_log(WLR_DEBUG, "DMA-BUF imported into parent Wayland compositor");
}
static void dmabuf_handle_failed(void *data_, struct zwp_linux_buffer_params_v1 *params) {
struct dmabuf_listener_data *data = data_;
data->done = true;
wlr_log(WLR_ERROR, "Failed to import DMA-BUF into parent Wayland compositor");
}
static const struct zwp_linux_buffer_params_v1_listener dmabuf_listener = {
.created = dmabuf_handle_created,
.failed = dmabuf_handle_failed,
};
static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl,
struct wlr_dmabuf_attributes *dmabuf) {
uint32_t modifier_hi = dmabuf->modifier >> 32;
@ -239,35 +187,18 @@ static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl,
dmabuf->offset[i], dmabuf->stride[i], modifier_hi, modifier_lo);
}
struct dmabuf_listener_data data = {0};
zwp_linux_buffer_params_v1_add_listener(params, &dmabuf_listener, &data);
zwp_linux_buffer_params_v1_create(params, dmabuf->width, dmabuf->height, dmabuf->format, 0);
struct wl_event_queue *display_queue =
wl_proxy_get_queue((struct wl_proxy *)wl->remote_display);
wl_proxy_set_queue((struct wl_proxy *)params, wl->busy_loop_queue);
while (!data.done) {
if (wl_display_dispatch_queue(wl->remote_display, wl->busy_loop_queue) < 0) {
wlr_log(WLR_ERROR, "wl_display_dispatch_queue() failed");
break;
}
}
struct wl_buffer *buffer = data.wl_buffer;
if (buffer != NULL) {
wl_proxy_set_queue((struct wl_proxy *)buffer, display_queue);
}
struct wl_buffer *wl_buffer = zwp_linux_buffer_params_v1_create_immed(
params, dmabuf->width, dmabuf->height, dmabuf->format, 0);
zwp_linux_buffer_params_v1_destroy(params);
return buffer;
// TODO: handle create() errors
return wl_buffer;
}
static struct wl_buffer *import_shm(struct wlr_wl_backend *wl,
struct wlr_shm_attributes *shm) {
enum wl_shm_format wl_shm_format = convert_drm_format_to_wl_shm(shm->format);
uint32_t size = shm->stride * shm->height;
struct wl_shm_pool *pool = wl_shm_create_pool(wl->shm, shm->fd, shm->offset + size);
struct wl_shm_pool *pool = wl_shm_create_pool(wl->shm, shm->fd, size);
if (pool == NULL) {
return NULL;
}
@ -331,58 +262,6 @@ static struct wlr_wl_buffer *get_or_create_wl_buffer(struct wlr_wl_backend *wl,
return create_wl_buffer(wl, wlr_buffer);
}
void destroy_wl_drm_syncobj_timeline(struct wlr_wl_drm_syncobj_timeline *timeline) {
wp_linux_drm_syncobj_timeline_v1_destroy(timeline->wl);
wlr_addon_finish(&timeline->addon);
wl_list_remove(&timeline->link);
free(timeline);
}
static void drm_syncobj_timeline_addon_destroy(struct wlr_addon *addon) {
struct wlr_wl_drm_syncobj_timeline *timeline = wl_container_of(addon, timeline, addon);
destroy_wl_drm_syncobj_timeline(timeline);
}
static const struct wlr_addon_interface drm_syncobj_timeline_addon_impl = {
.name = "wlr_wl_drm_syncobj_timeline",
.destroy = drm_syncobj_timeline_addon_destroy,
};
static struct wlr_wl_drm_syncobj_timeline *get_or_create_drm_syncobj_timeline(
struct wlr_wl_backend *wl, struct wlr_drm_syncobj_timeline *wlr_timeline) {
struct wlr_addon *addon =
wlr_addon_find(&wlr_timeline->addons, wl, &drm_syncobj_timeline_addon_impl);
if (addon != NULL) {
struct wlr_wl_drm_syncobj_timeline *timeline = wl_container_of(addon, timeline, addon);
return timeline;
}
struct wlr_wl_drm_syncobj_timeline *timeline = calloc(1, sizeof(*timeline));
if (timeline == NULL) {
return NULL;
}
timeline->base = wlr_timeline;
int fd = wlr_drm_syncobj_timeline_export(wlr_timeline);
if (fd < 0) {
free(timeline);
return NULL;
}
timeline->wl = wp_linux_drm_syncobj_manager_v1_import_timeline(wl->drm_syncobj_manager_v1, fd);
close(fd);
if (timeline->wl == NULL) {
free(timeline);
return NULL;
}
wlr_addon_init(&timeline->addon, &wlr_timeline->addons, wl, &drm_syncobj_timeline_addon_impl);
wl_list_insert(&wl->drm_syncobj_timelines, &timeline->link);
return timeline;
}
static bool update_title(struct wlr_wl_output *output, const char *title) {
struct wlr_output *wlr_output = &output->wlr_output;
@ -422,28 +301,6 @@ static bool output_test(struct wlr_output *wlr_output,
struct wlr_wl_output *output =
get_wl_output_from_output(wlr_output);
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
// If the size doesn't match, reject buffer (scaling is not currently
// supported but could be implemented with viewporter)
int pending_width, pending_height;
output_pending_resolution(wlr_output, state,
&pending_width, &pending_height);
if (state->buffer->width != pending_width ||
state->buffer->height != pending_height) {
wlr_log(WLR_DEBUG, "Primary buffer size mismatch");
return false;
}
// Source crop is also not currently supported
struct wlr_fbox src_box;
output_state_get_buffer_src_box(state, &src_box);
if (src_box.x != 0.0 || src_box.y != 0.0 ||
src_box.width != (double)state->buffer->width ||
src_box.height != (double)state->buffer->height) {
wlr_log(WLR_DEBUG, "Source crop not supported in wayland output");
return false;
}
}
uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE;
if (unsupported != 0) {
wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32,
@ -477,21 +334,6 @@ static bool output_test(struct wlr_output *wlr_output,
return false;
}
if ((state->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) &&
!(state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE)) {
wlr_log(WLR_DEBUG, "Signal timeline requires a wait timeline");
return false;
}
if ((state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) ||
(state->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE)) {
struct wlr_dmabuf_attributes dmabuf;
if (!wlr_buffer_get_dmabuf(state->buffer, &dmabuf)) {
wlr_log(WLR_DEBUG, "Wait/signal timelines require DMA-BUFs");
return false;
}
}
if (state->committed & WLR_OUTPUT_STATE_LAYERS) {
// If we can't use a sub-surface for a layer, then we can't use a
// sub-surface for any layer underneath
@ -723,15 +565,15 @@ static const struct wl_callback_listener unmap_callback_listener = {
.done = unmap_callback_handle_done,
};
static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output_state *state) {
struct wlr_wl_output *output = get_wl_output_from_output(wlr_output);
static bool output_commit(struct wlr_output *wlr_output,
const struct wlr_output_state *state) {
struct wlr_wl_output *output =
get_wl_output_from_output(wlr_output);
if (!output_test(wlr_output, state)) {
return false;
}
struct wlr_wl_backend *wl = output->backend;
bool pending_enabled = output_pending_enabled(wlr_output, state);
if (wlr_output->enabled && !pending_enabled) {
@ -756,28 +598,15 @@ static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output
wl_surface_commit(output->surface);
output->initialized = true;
struct wl_event_queue *display_queue =
wl_proxy_get_queue((struct wl_proxy *)wl->remote_display);
wl_proxy_set_queue((struct wl_proxy *)output->xdg_surface, wl->busy_loop_queue);
wl_proxy_set_queue((struct wl_proxy *)output->xdg_toplevel, wl->busy_loop_queue);
wl_display_flush(wl->remote_display);
wl_display_flush(output->backend->remote_display);
while (!output->configured) {
if (wl_display_dispatch_queue(wl->remote_display, wl->busy_loop_queue) == -1) {
wlr_log(WLR_ERROR, "wl_display_dispatch_queue() failed");
break;
if (wl_display_dispatch(output->backend->remote_display) == -1) {
wlr_log(WLR_ERROR, "wl_display_dispatch() failed");
return false;
}
}
wl_proxy_set_queue((struct wl_proxy *)output->xdg_surface, display_queue);
wl_proxy_set_queue((struct wl_proxy *)output->xdg_toplevel, display_queue);
if (!output->configured) {
return false;
}
}
struct wlr_wl_buffer *buffer = NULL;
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
const pixman_region32_t *damage = NULL;
if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
@ -785,7 +614,8 @@ static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output
}
struct wlr_buffer *wlr_buffer = state->buffer;
buffer = get_or_create_wl_buffer(wl, wlr_buffer);
struct wlr_wl_buffer *buffer =
get_or_create_wl_buffer(output->backend, wlr_buffer);
if (buffer == NULL) {
return false;
}
@ -794,63 +624,6 @@ static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output
damage_surface(output->surface, damage);
}
if (state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
struct wlr_wl_drm_syncobj_timeline *wait_timeline =
get_or_create_drm_syncobj_timeline(wl, state->wait_timeline);
struct wlr_wl_drm_syncobj_timeline *signal_timeline;
uint64_t signal_point;
if (state->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
signal_timeline = get_or_create_drm_syncobj_timeline(wl, state->signal_timeline);
signal_point = state->signal_point;
} else {
if (buffer->fallback_signal_timeline == NULL) {
buffer->fallback_signal_timeline =
wlr_drm_syncobj_timeline_create(wl->drm_fd);
if (buffer->fallback_signal_timeline == NULL) {
return false;
}
}
signal_timeline =
get_or_create_drm_syncobj_timeline(wl, buffer->fallback_signal_timeline);
signal_point = ++buffer->fallback_signal_point;
}
if (wait_timeline == NULL || signal_timeline == NULL) {
return false;
}
if (output->drm_syncobj_surface_v1 == NULL) {
output->drm_syncobj_surface_v1 = wp_linux_drm_syncobj_manager_v1_get_surface(
wl->drm_syncobj_manager_v1, output->surface);
if (output->drm_syncobj_surface_v1 == NULL) {
return false;
}
}
uint32_t wait_point_hi = state->wait_point >> 32;
uint32_t wait_point_lo = state->wait_point & UINT32_MAX;
uint32_t signal_point_hi = signal_point >> 32;
uint32_t signal_point_lo = signal_point & UINT32_MAX;
wp_linux_drm_syncobj_surface_v1_set_acquire_point(output->drm_syncobj_surface_v1,
wait_timeline->wl, wait_point_hi, wait_point_lo);
wp_linux_drm_syncobj_surface_v1_set_release_point(output->drm_syncobj_surface_v1,
signal_timeline->wl, signal_point_hi, signal_point_lo);
if (!wlr_drm_syncobj_timeline_waiter_init(&buffer->drm_syncobj_waiter,
signal_timeline->base, signal_point, 0, wl->event_loop,
buffer_handle_drm_syncobj_ready)) {
return false;
}
buffer->has_drm_syncobj_waiter = true;
} else {
if (output->drm_syncobj_surface_v1 != NULL) {
wp_linux_drm_syncobj_surface_v1_destroy(output->drm_syncobj_surface_v1);
output->drm_syncobj_surface_v1 = NULL;
}
}
if ((state->committed & WLR_OUTPUT_STATE_LAYERS) &&
!commit_layers(output, state->layers, state->layers_len)) {
return false;
@ -864,8 +637,9 @@ static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output
wl_callback_add_listener(output->frame_callback, &frame_listener, output);
struct wp_presentation_feedback *wp_feedback = NULL;
if (wl->presentation != NULL) {
wp_feedback = wp_presentation_feedback(wl->presentation, output->surface);
if (output->backend->presentation != NULL) {
wp_feedback = wp_presentation_feedback(output->backend->presentation,
output->surface);
}
if (output->has_configure_serial) {
@ -898,7 +672,7 @@ static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output
}
}
wl_display_flush(wl->remote_display);
wl_display_flush(output->backend->remote_display);
return true;
}
@ -954,8 +728,6 @@ static void output_destroy(struct wlr_output *wlr_output) {
return;
}
wlr_output_finish(wlr_output);
wl_list_remove(&output->link);
if (output->cursor.surface) {
@ -976,9 +748,6 @@ static void output_destroy(struct wlr_output *wlr_output) {
wl_callback_destroy(output->unmap_callback);
}
if (output->drm_syncobj_surface_v1) {
wp_linux_drm_syncobj_surface_v1_destroy(output->drm_syncobj_surface_v1);
}
if (output->zxdg_toplevel_decoration_v1) {
zxdg_toplevel_decoration_v1_destroy(output->zxdg_toplevel_decoration_v1);
}
@ -1055,12 +824,6 @@ static void xdg_surface_handle_configure(void *data,
output->has_configure_serial = true;
output->configure_serial = serial;
if (!output->wlr_output.enabled) {
// We're waiting for a configure event after an initial commit to enable
// the output. Do not notify the compositor about the requested state.
return;
}
struct wlr_output_state state;
wlr_output_state_init(&state);
wlr_output_state_set_custom_mode(&state, req_width, req_height, 0);

View file

@ -112,7 +112,7 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
.state = state,
.time_msec = time,
};
wlr_pointer_notify_button(&pointer->wlr_pointer, &event);
wl_signal_emit_mutable(&pointer->wlr_pointer.events.button, &event);
}
static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,

View file

@ -27,14 +27,12 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
struct wlr_keyboard *keyboard = data;
int64_t time_msec = get_current_time_msec();
uint32_t *keycode_ptr;
wl_array_for_each(keycode_ptr, keys) {
struct wlr_keyboard_key_event event = {
.keycode = *keycode_ptr,
.state = WL_KEYBOARD_KEY_STATE_PRESSED,
.time_msec = time_msec,
.time_msec = get_current_time_msec(),
.update_state = false,
};
wlr_keyboard_notify_key(keyboard, &event);
@ -45,12 +43,18 @@ static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
uint32_t serial, struct wl_surface *surface) {
struct wlr_keyboard *keyboard = data;
int64_t time_msec = get_current_time_msec();
while (keyboard->num_keycodes > 0) {
size_t num_keycodes = keyboard->num_keycodes;
uint32_t pressed[num_keycodes + 1];
memcpy(pressed, keyboard->keycodes,
num_keycodes * sizeof(uint32_t));
for (size_t i = 0; i < num_keycodes; ++i) {
uint32_t keycode = pressed[i];
struct wlr_keyboard_key_event event = {
.keycode = keyboard->keycodes[keyboard->num_keycodes - 1],
.keycode = keycode,
.state = WL_KEYBOARD_KEY_STATE_RELEASED,
.time_msec = time_msec,
.time_msec = get_current_time_msec(),
.update_state = false,
};
wlr_keyboard_notify_key(keyboard, &event);

View file

@ -212,10 +212,17 @@ static int backend_get_drm_fd(struct wlr_backend *backend) {
return x11->drm_fd;
}
static uint32_t get_buffer_caps(struct wlr_backend *backend) {
struct wlr_x11_backend *x11 = get_x11_backend_from_backend(backend);
return (x11->have_dri3 ? WLR_BUFFER_CAP_DMABUF : 0)
| (x11->have_shm ? WLR_BUFFER_CAP_SHM : 0);
}
static const struct wlr_backend_impl backend_impl = {
.start = backend_start,
.destroy = backend_destroy,
.get_drm_fd = backend_get_drm_fd,
.get_buffer_caps = get_buffer_caps,
};
bool wlr_backend_is_x11(struct wlr_backend *backend) {
@ -402,7 +409,7 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
wl_list_init(&x11->outputs);
x11->xcb = xcb_connect(x11_display, NULL);
if (xcb_connection_has_error(x11->xcb)) {
if (!x11->xcb || xcb_connection_has_error(x11->xcb)) {
wlr_log(WLR_ERROR, "Failed to open xcb connection");
goto error_x11;
}
@ -505,10 +512,7 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
xcb_present_query_version(x11->xcb, 1, 2);
xcb_present_query_version_reply_t *present_reply =
xcb_present_query_version_reply(x11->xcb, present_cookie, NULL);
if (!present_reply) {
wlr_log(WLR_ERROR, "Failed to query Present version");
goto error_display;
} else if (present_reply->major_version < 1) {
if (!present_reply || present_reply->major_version < 1) {
wlr_log(WLR_ERROR, "X11 does not support required Present version "
"(has %"PRIu32".%"PRIu32", want 1.0)",
present_reply->major_version, present_reply->minor_version);
@ -529,10 +533,7 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
xcb_xfixes_query_version(x11->xcb, 4, 0);
xcb_xfixes_query_version_reply_t *fixes_reply =
xcb_xfixes_query_version_reply(x11->xcb, fixes_cookie, NULL);
if (!fixes_reply) {
wlr_log(WLR_ERROR, "Failed to query Xfixes version");
goto error_display;
} else if (fixes_reply->major_version < 4) {
if (!fixes_reply || fixes_reply->major_version < 4) {
wlr_log(WLR_ERROR, "X11 does not support required Xfixes version "
"(has %"PRIu32".%"PRIu32", want 4.0)",
fixes_reply->major_version, fixes_reply->minor_version);
@ -554,10 +555,7 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
xcb_input_xi_query_version(x11->xcb, 2, 0);
xcb_input_xi_query_version_reply_t *xi_reply =
xcb_input_xi_query_version_reply(x11->xcb, xi_cookie, NULL);
if (!xi_reply) {
wlr_log(WLR_ERROR, "Failed to query Xinput version");
goto error_display;
} else if (xi_reply->major_version < 2) {
if (!xi_reply || xi_reply->major_version < 2) {
wlr_log(WLR_ERROR, "X11 does not support required Xinput version "
"(has %"PRIu32".%"PRIu32", want 2.0)",
xi_reply->major_version, xi_reply->minor_version);
@ -566,13 +564,6 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_event_loop *loop,
}
free(xi_reply);
if (x11->have_dri3) {
x11->backend.buffer_caps |= WLR_BUFFER_CAP_DMABUF;
}
if (x11->have_shm) {
x11->backend.buffer_caps |= WLR_BUFFER_CAP_SHM;
}
int fd = xcb_get_file_descriptor(x11->xcb);
uint32_t events = WL_EVENT_READABLE | WL_EVENT_ERROR | WL_EVENT_HANGUP;
x11->event_source = wl_event_loop_add_fd(loop, fd, events, x11_event, x11);

View file

@ -36,7 +36,7 @@ static void send_button_event(struct wlr_x11_output *output, uint32_t key,
.button = key,
.state = st,
};
wlr_pointer_notify_button(&output->pointer, &ev);
wl_signal_emit_mutable(&output->pointer.events.button, &ev);
wl_signal_emit_mutable(&output->pointer.events.frame, &output->pointer);
}

View file

@ -94,8 +94,6 @@ static void output_destroy(struct wlr_output *wlr_output) {
struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
struct wlr_x11_backend *x11 = output->x11;
wlr_output_finish(wlr_output);
pixman_region32_fini(&output->exposed);
wlr_pointer_finish(&output->pointer);
@ -131,27 +129,6 @@ static bool output_test(struct wlr_output *wlr_output,
return false;
}
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
// If the size doesn't match, reject buffer (scaling is not supported)
int pending_width, pending_height;
output_pending_resolution(wlr_output, state,
&pending_width, &pending_height);
if (state->buffer->width != pending_width ||
state->buffer->height != pending_height) {
wlr_log(WLR_DEBUG, "Primary buffer size mismatch");
return false;
}
// Source crop is not supported
struct wlr_fbox src_box;
output_state_get_buffer_src_box(state, &src_box);
if (src_box.x != 0.0 || src_box.y != 0.0 ||
src_box.width != (double)state->buffer->width ||
src_box.height != (double)state->buffer->height) {
wlr_log(WLR_DEBUG, "Source crop not supported in X11 output");
return false;
}
}
// All we can do to influence adaptive sync on the X11 backend is set the
// _VARIABLE_REFRESH window property like mesa automatically does. We don't
// have any control beyond that, so we set the state to enabled on creating
@ -770,6 +747,9 @@ void handle_x11_present_event(struct wlr_x11_backend *x11,
output->last_msc = complete_notify->msc;
struct timespec t;
timespec_from_nsec(&t, complete_notify->ust * 1000);
uint32_t flags = 0;
if (complete_notify->mode == XCB_PRESENT_COMPLETE_MODE_FLIP) {
flags |= WLR_OUTPUT_PRESENT_ZERO_COPY;
@ -780,10 +760,10 @@ void handle_x11_present_event(struct wlr_x11_backend *x11,
.output = &output->wlr_output,
.commit_seq = complete_notify->serial,
.presented = presented,
.when = &t,
.seq = complete_notify->msc,
.flags = flags,
};
timespec_from_nsec(&present_event.when, complete_notify->ust * 1000);
wlr_output_send_present(&output->wlr_output, &present_event);
wlr_output_send_frame(&output->wlr_output);

View file

@ -12,10 +12,6 @@ wlroots reads these environment variables
renderers: gles2, pixman, vulkan)
* *WLR_RENDER_DRM_DEVICE*: specifies the DRM node to use for
hardware-accelerated renderers.
* *WLR_RENDER_NO_EXPLICIT_SYNC*: set to 1 to disable explicit synchronization
support in renderers.
* *WLR_RENDERER_FORCE_SOFTWARE*: set to 1 to force software rendering for GLES2
and Vulkan
* *WLR_EGL_NO_MODIFIERS*: set to 1 to disable format modifiers in EGL, this can
be used to understand and work around driver bugs.

View file

@ -24,7 +24,6 @@ struct cairo_buffer {
static void cairo_buffer_destroy(struct wlr_buffer *wlr_buffer) {
struct cairo_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
wlr_buffer_finish(wlr_buffer);
cairo_surface_destroy(buffer->surface);
free(buffer);
}

258
examples/fullscreen-shell.c Normal file
View file

@ -0,0 +1,258 @@
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <wayland-server-core.h>
#include <wlr/backend.h>
#include <wlr/render/allocator.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_fullscreen_shell_v1.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
#include <wlr/util/box.h>
#include <wlr/util/log.h>
#include <wlr/util/transform.h>
/**
* A minimal fullscreen-shell server. It only supports rendering.
*/
struct fullscreen_server {
struct wl_display *wl_display;
struct wlr_backend *backend;
struct wlr_renderer *renderer;
struct wlr_allocator *allocator;
struct wlr_fullscreen_shell_v1 *fullscreen_shell;
struct wl_listener present_surface;
struct wlr_output_layout *output_layout;
struct wl_list outputs;
struct wl_listener new_output;
};
struct fullscreen_output {
struct wl_list link;
struct fullscreen_server *server;
struct wlr_output *wlr_output;
struct wlr_surface *surface;
struct wl_listener surface_destroy;
struct wl_listener frame;
};
struct render_data {
struct wlr_output *output;
struct wlr_render_pass *render_pass;
struct timespec *when;
};
static void render_surface(struct wlr_surface *surface,
int sx, int sy, void *data) {
struct render_data *rdata = data;
struct wlr_output *output = rdata->output;
struct wlr_texture *texture = wlr_surface_get_texture(surface);
if (texture == NULL) {
return;
}
struct wlr_box box = {
.x = sx * output->scale,
.y = sy * output->scale,
.width = surface->current.width * output->scale,
.height = surface->current.height * output->scale,
};
enum wl_output_transform transform = wlr_output_transform_invert(surface->current.transform);
transform = wlr_output_transform_compose(transform, output->transform);
wlr_render_pass_add_texture(rdata->render_pass, &(struct wlr_render_texture_options){
.texture = texture,
.dst_box = box,
.transform = transform,
});
wlr_surface_send_frame_done(surface, rdata->when);
}
static void output_handle_frame(struct wl_listener *listener, void *data) {
struct fullscreen_output *output =
wl_container_of(listener, output, frame);
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
int width, height;
wlr_output_effective_resolution(output->wlr_output, &width, &height);
struct wlr_output_state state;
wlr_output_state_init(&state);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, &state, NULL,
NULL);
if (pass == NULL) {
return;
}
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
.color = { 0.3, 0.3, 0.3, 1.0 },
.box = { .width = width, .height = height },
});
if (output->surface != NULL) {
struct render_data rdata = {
.output = output->wlr_output,
.render_pass = pass,
.when = &now,
};
wlr_surface_for_each_surface(output->surface, render_surface, &rdata);
}
wlr_render_pass_submit(pass);
wlr_output_commit_state(output->wlr_output, &state);
wlr_output_state_finish(&state);
}
static void output_set_surface(struct fullscreen_output *output,
struct wlr_surface *surface);
static void output_handle_surface_destroy(struct wl_listener *listener,
void *data) {
struct fullscreen_output *output =
wl_container_of(listener, output, surface_destroy);
output_set_surface(output, NULL);
}
static void output_set_surface(struct fullscreen_output *output,
struct wlr_surface *surface) {
if (output->surface == surface) {
return;
}
if (output->surface != NULL) {
wl_list_remove(&output->surface_destroy.link);
output->surface = NULL;
}
if (surface != NULL) {
output->surface_destroy.notify = output_handle_surface_destroy;
wl_signal_add(&surface->events.destroy, &output->surface_destroy);
output->surface = surface;
}
wlr_log(WLR_DEBUG, "Presenting surface %p on output %s",
surface, output->wlr_output->name);
}
static void server_handle_new_output(struct wl_listener *listener, void *data) {
struct fullscreen_server *server =
wl_container_of(listener, server, new_output);
struct wlr_output *wlr_output = data;
wlr_output_init_render(wlr_output, server->allocator, server->renderer);
struct fullscreen_output *output = calloc(1, sizeof(*output));
output->wlr_output = wlr_output;
output->server = server;
output->frame.notify = output_handle_frame;
wl_signal_add(&wlr_output->events.frame, &output->frame);
wl_list_insert(&server->outputs, &output->link);
wlr_output_layout_add_auto(server->output_layout, wlr_output);
wlr_output_create_global(wlr_output, server->wl_display);
struct wlr_output_state state;
wlr_output_state_init(&state);
wlr_output_state_set_enabled(&state, true);
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
if (mode != NULL) {
wlr_output_state_set_mode(&state, mode);
}
wlr_output_commit_state(wlr_output, &state);
wlr_output_state_finish(&state);
}
static void server_handle_present_surface(struct wl_listener *listener,
void *data) {
struct fullscreen_server *server =
wl_container_of(listener, server, present_surface);
struct wlr_fullscreen_shell_v1_present_surface_event *event = data;
struct fullscreen_output *output;
wl_list_for_each(output, &server->outputs, link) {
if (event->output == NULL || event->output == output->wlr_output) {
output_set_surface(output, event->surface);
}
}
}
int main(int argc, char *argv[]) {
wlr_log_init(WLR_DEBUG, NULL);
char *startup_cmd = NULL;
int c;
while ((c = getopt(argc, argv, "s:")) != -1) {
switch (c) {
case 's':
startup_cmd = optarg;
break;
default:
printf("usage: %s [-s startup-command]\n", argv[0]);
return EXIT_FAILURE;
}
}
if (optind < argc) {
printf("usage: %s [-s startup-command]\n", argv[0]);
return EXIT_FAILURE;
}
struct fullscreen_server server = {0};
server.wl_display = wl_display_create();
server.backend = wlr_backend_autocreate(wl_display_get_event_loop(server.wl_display), NULL);
server.renderer = wlr_renderer_autocreate(server.backend);
wlr_renderer_init_wl_display(server.renderer, server.wl_display);
server.allocator = wlr_allocator_autocreate(server.backend,
server.renderer);
wlr_compositor_create(server.wl_display, 5, server.renderer);
server.output_layout = wlr_output_layout_create(server.wl_display);
wl_list_init(&server.outputs);
server.new_output.notify = server_handle_new_output;
wl_signal_add(&server.backend->events.new_output, &server.new_output);
server.fullscreen_shell = wlr_fullscreen_shell_v1_create(server.wl_display);
server.present_surface.notify = server_handle_present_surface;
wl_signal_add(&server.fullscreen_shell->events.present_surface,
&server.present_surface);
const char *socket = wl_display_add_socket_auto(server.wl_display);
if (!socket) {
wl_display_destroy(server.wl_display);
return EXIT_FAILURE;
}
if (!wlr_backend_start(server.backend)) {
wl_display_destroy(server.wl_display);
return EXIT_FAILURE;
}
setenv("WAYLAND_DISPLAY", socket, true);
if (startup_cmd != NULL) {
if (fork() == 0) {
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, (void *)NULL);
}
}
wlr_log(WLR_INFO, "Running Wayland compositor on WAYLAND_DISPLAY=%s",
socket);
wl_display_run(server.wl_display);
wl_display_destroy_clients(server.wl_display);
wl_display_destroy(server.wl_display);
return 0;
}

View file

@ -25,6 +25,10 @@ compositors = {
'output-layout': {
'src': ['output-layout.c', 'cat.c'],
},
'fullscreen-shell': {
'src': 'fullscreen-shell.c',
'proto': ['fullscreen-shell-unstable-v1'],
},
'scene-graph': {
'src': 'scene-graph.c',
'proto': ['xdg-shell'],

View file

@ -94,7 +94,9 @@ static void output_handle_frame(struct wl_listener *listener, void *data) {
int width, height;
wlr_output_effective_resolution(output->wlr_output, &width, &height);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, &output_state, NULL);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(output->wlr_output, &output_state,
NULL, NULL);
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
.box = { .width = width, .height = height },
.color = { 0.3, 0.3, 0.3, 1 },

View file

@ -114,7 +114,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
struct wlr_output_state output_state;
wlr_output_state_init(&output_state);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
.box = { .width = wlr_output->width, .height = wlr_output->height },

View file

@ -101,7 +101,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
struct wlr_output_state output_state;
wlr_output_state_init(&output_state);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
.box = { .width = wlr_output->width, .height = wlr_output->height },
.color = {

View file

@ -59,7 +59,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
struct wlr_output_state output_state;
wlr_output_state_init(&output_state);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
.box = { .width = wlr_output->width, .height = wlr_output->height },

View file

@ -63,7 +63,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
struct wlr_output_state state;
wlr_output_state_init(&state);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &state, NULL);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &state, NULL, NULL);
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
.box = { .width = wlr_output->width, .height = wlr_output->height },
.color = {

View file

@ -89,7 +89,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
struct wlr_output_state output_state;
wlr_output_state_init(&output_state);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
.box = { .width = wlr_output->width, .height = wlr_output->height },

View file

@ -76,7 +76,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
struct wlr_output_state output_state;
wlr_output_state_init(&output_state);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL);
struct wlr_render_pass *pass = wlr_output_begin_render_pass(wlr_output, &output_state, NULL, NULL);
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
.box = { .width = width, .height = height },
.color = { 0.25, 0.25, 0.25, 1 },

13
include/backend/backend.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef BACKEND_WLR_BACKEND_H
#define BACKEND_WLR_BACKEND_H
#include <wlr/backend.h>
/**
* Get the supported buffer capabilities.
*
* This functions returns a bitfield of supported wlr_buffer_cap.
*/
uint32_t backend_get_buffer_caps(struct wlr_backend *backend);
#endif

View file

@ -15,11 +15,6 @@
#include "backend/drm/properties.h"
#include "backend/drm/renderer.h"
struct wlr_drm_viewport {
struct wlr_fbox src_box;
struct wlr_box dst_box;
};
struct wlr_drm_plane {
uint32_t type;
uint32_t id;
@ -31,8 +26,6 @@ struct wlr_drm_plane {
struct wlr_drm_fb *queued_fb;
/* Buffer currently displayed on screen */
struct wlr_drm_fb *current_fb;
/* Viewport belonging to the last committed fb */
struct wlr_drm_viewport viewport;
struct wlr_drm_format_set formats;
@ -146,20 +139,13 @@ struct wlr_drm_connector_state {
bool active;
drmModeModeInfo mode;
struct wlr_drm_fb *primary_fb;
struct wlr_drm_viewport primary_viewport;
struct wlr_drm_fb *cursor_fb;
struct wlr_drm_syncobj_timeline *wait_timeline;
uint64_t wait_point;
// used by atomic
uint32_t mode_id;
uint32_t gamma_lut;
uint32_t fb_damage_clips;
int primary_in_fence_fd, out_fence_fd;
bool vrr_enabled;
uint32_t colorspace;
uint32_t hdr_output_metadata;
};
/**
@ -214,10 +200,6 @@ struct wlr_drm_connector {
// Last committed page-flip
struct wlr_drm_page_flip *pending_page_flip;
// Atomic modesetting only
uint32_t colorspace;
uint32_t hdr_output_metadata;
int32_t refresh;
};
@ -231,6 +213,7 @@ void scan_drm_connectors(struct wlr_drm_backend *state,
void scan_drm_leases(struct wlr_drm_backend *drm);
bool commit_drm_device(struct wlr_drm_backend *drm,
const struct wlr_backend_output_state *states, size_t states_len, bool test_only);
void restore_drm_device(struct wlr_drm_backend *drm);
int handle_drm_event(int fd, uint32_t mask, void *data);
void destroy_drm_connector(struct wlr_drm_connector *conn);
bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn);

View file

@ -2,10 +2,6 @@
#define BACKEND_DRM_FB_H
#include <stdbool.h>
#include <stdint.h>
#include <wlr/util/addon.h>
struct wlr_drm_format_set;
struct wlr_drm_fb {
struct wlr_buffer *wlr_buf;

View file

@ -22,6 +22,8 @@ struct wlr_drm_interface {
bool (*commit)(struct wlr_drm_backend *drm,
const struct wlr_drm_device_state *state,
struct wlr_drm_page_flip *page_flip, uint32_t flags, bool test_only);
// Turn off everything
bool (*reset)(struct wlr_drm_backend *drm);
};
extern const struct wlr_drm_interface atomic_iface;

View file

@ -26,8 +26,6 @@ struct wlr_drm_connector_props {
// atomic-modesetting only
uint32_t crtc_id;
uint32_t colorspace;
uint32_t hdr_output_metadata;
};
struct wlr_drm_crtc_props {
@ -40,7 +38,6 @@ struct wlr_drm_crtc_props {
uint32_t active;
uint32_t mode_id;
uint32_t out_fence_ptr;
};
struct wlr_drm_plane_props {
@ -64,7 +61,6 @@ struct wlr_drm_plane_props {
uint32_t fb_damage_clips;
uint32_t hotspot_x;
uint32_t hotspot_y;
uint32_t in_fence_fd;
};
bool get_drm_connector_props(int fd, uint32_t id,

View file

@ -20,9 +20,6 @@ struct wlr_drm_renderer {
struct wlr_drm_surface {
struct wlr_drm_renderer *renderer;
struct wlr_swapchain *swapchain;
struct wlr_drm_syncobj_timeline *timeline;
uint64_t point;
};
bool init_drm_renderer(struct wlr_drm_backend *drm,
@ -35,8 +32,7 @@ bool init_drm_surface(struct wlr_drm_surface *surf,
void finish_drm_surface(struct wlr_drm_surface *surf);
struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
struct wlr_buffer *buffer,
struct wlr_drm_syncobj_timeline *wait_timeline, uint64_t wait_point);
struct wlr_buffer *buffer);
bool drm_plane_pick_render_format(struct wlr_drm_plane *plane,
struct wlr_drm_format *fmt, struct wlr_drm_renderer *renderer);

View file

@ -18,24 +18,26 @@ const char *drm_connector_status_str(drmModeConnection status);
void generate_cvt_mode(drmModeModeInfo *mode, int hdisplay, int vdisplay,
float vrefresh);
// Part of match_connectors_with_crtcs
#define UNMATCHED ((uint32_t)-1)
// Part of match_obj
enum {
UNMATCHED = (uint32_t)-1,
SKIP = (uint32_t)-2,
};
/**
* Tries to match DRM connectors with DRM CRTCs.
/*
* Tries to match some DRM objects with some other DRM resource.
* e.g. Match CRTCs with Encoders, CRTCs with Planes.
*
* conns contains an array of bitmasks describing compatible CRTCs. For
* instance bit 0 set in an connector element means that it's compatible with
* CRTC 0.
* objs contains a bit array which resources it can be matched with.
* e.g. Bit 0 set means can be matched with res[0]
*
* prev_crtcs contains connector indices each CRTC was previously matched with,
* or UNMATCHED.
* res contains an index of which objs it is matched with or UNMATCHED.
*
* new_crtcs is populated with the new connector indices.
* This solution is left in out.
* Returns the total number of matched solutions.
*/
void match_connectors_with_crtcs(size_t num_conns,
const uint32_t conns[static restrict num_conns],
size_t num_crtcs, const uint32_t prev_crtcs[static restrict num_crtcs],
uint32_t new_crtcs[static restrict num_crtcs]);
size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs],
size_t num_res, const uint32_t res[static restrict num_res],
uint32_t out[static restrict num_res]);
#endif

View file

@ -12,6 +12,8 @@
#include <wlr/types/wlr_tablet_tool.h>
#include <wlr/types/wlr_touch.h>
#include "config.h"
struct wlr_libinput_backend {
struct wlr_backend backend;

View file

@ -14,7 +14,6 @@
#include <wlr/types/wlr_tablet_tool.h>
#include <wlr/types/wlr_touch.h>
#include <wlr/render/drm_format_set.h>
#include <wlr/render/drm_syncobj.h>
struct wlr_wl_backend {
struct wlr_backend backend;
@ -22,7 +21,6 @@ struct wlr_wl_backend {
/* local state */
bool started;
struct wl_event_loop *event_loop;
struct wl_event_queue *busy_loop_queue;
struct wl_list outputs;
int drm_fd;
struct wl_list buffers; // wlr_wl_buffer.link
@ -42,8 +40,6 @@ struct wlr_wl_backend {
struct wp_presentation *presentation;
struct wl_shm *shm;
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1;
struct wp_linux_drm_syncobj_manager_v1 *drm_syncobj_manager_v1;
struct wl_list drm_syncobj_timelines; // wlr_wl_drm_syncobj_timeline.link
struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1;
struct wl_list seats; // wlr_wl_seat.link
struct zwp_tablet_manager_v2 *tablet_manager;
@ -62,19 +58,6 @@ struct wlr_wl_buffer {
bool released;
struct wl_list link; // wlr_wl_backend.buffers
struct wl_listener buffer_destroy;
bool has_drm_syncobj_waiter;
struct wlr_drm_syncobj_timeline_waiter drm_syncobj_waiter;
struct wlr_drm_syncobj_timeline *fallback_signal_timeline;
uint64_t fallback_signal_point;
};
struct wlr_wl_drm_syncobj_timeline {
struct wlr_drm_syncobj_timeline *base;
struct wlr_addon addon;
struct wl_list link; // wlr_wl_backend.drm_syncobj_timelines
struct wp_linux_drm_syncobj_timeline_v1 *wl;
};
struct wlr_wl_presentation_feedback {
@ -105,7 +88,6 @@ struct wlr_wl_output {
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1;
struct wp_linux_drm_syncobj_surface_v1 *drm_syncobj_surface_v1;
struct wl_list presentation_feedbacks;
char *title;
@ -208,7 +190,6 @@ bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl,
uint32_t global_name);
void destroy_wl_seat(struct wlr_wl_seat *seat);
void destroy_wl_buffer(struct wlr_wl_buffer *buffer);
void destroy_wl_drm_syncobj_timeline(struct wlr_wl_drm_syncobj_timeline *timeline);
extern const struct wlr_pointer_impl wl_pointer_impl;
extern const struct wlr_tablet_pad_impl wl_tablet_pad_impl;

View file

@ -0,0 +1,9 @@
#ifndef RENDER_ALLOCATOR_ALLOCATOR_H
#define RENDER_ALLOCATOR_ALLOCATOR_H
#include <wlr/render/allocator.h>
struct wlr_allocator *allocator_autocreate_with_drm_fd(
uint32_t backend_caps, struct wlr_renderer *renderer, int drm_fd);
#endif

View file

@ -1,9 +1,9 @@
#ifndef RENDER_ALLOCATOR_DRM_DUMB_H
#define RENDER_ALLOCATOR_DRM_DUMB_H
#include <wlr/render/allocator.h>
#include <wlr/render/dmabuf.h>
#include <wlr/types/wlr_buffer.h>
#include "render/allocator/allocator.h"
struct wlr_drm_dumb_buffer {
struct wlr_buffer base;

View file

@ -2,9 +2,9 @@
#define RENDER_ALLOCATOR_GBM_H
#include <gbm.h>
#include <wlr/render/allocator.h>
#include <wlr/render/dmabuf.h>
#include <wlr/types/wlr_buffer.h>
#include "render/allocator/allocator.h"
struct wlr_gbm_buffer {
struct wlr_buffer base;

View file

@ -1,8 +1,8 @@
#ifndef RENDER_ALLOCATOR_SHM_H
#define RENDER_ALLOCATOR_SHM_H
#include <wlr/render/allocator.h>
#include <wlr/types/wlr_buffer.h>
#include "render/allocator/allocator.h"
struct wlr_shm_buffer {
struct wlr_buffer base;

View file

@ -1,23 +0,0 @@
#ifndef RENDER_ALLOCATOR_UDMABUF_H
#define RENDER_ALLOCATOR_UDMABUF_H
#include <wlr/types/wlr_buffer.h>
#include <wlr/render/allocator.h>
struct wlr_udmabuf_buffer {
struct wlr_buffer base;
size_t size;
struct wlr_shm_attributes shm;
struct wlr_dmabuf_attributes dmabuf;
};
struct wlr_udmabuf_allocator {
struct wlr_allocator base;
int fd;
};
struct wlr_allocator *wlr_udmabuf_allocator_create(void);
#endif

View file

@ -2,14 +2,30 @@
#define RENDER_COLOR_H
#include <stdint.h>
#include <wlr/render/color.h>
#include <wlr/util/addon.h>
/**
* The formula is approximated via a 3D look-up table. A 3D LUT is a
* three-dimensional array where each element is an RGB triplet. The flat lut_3d
* array has a length of dim_len³.
*
* Color channel values in the range [0.0, 1.0] are mapped linearly to
* 3D LUT indices such that 0.0 maps exactly to the first element and 1.0 maps
* exactly to the last element in each dimension.
*
* The offset of the RGB triplet given red, green and blue indices r_index,
* g_index and b_index is:
*
* offset = 3 * (r_index + dim_len * g_index + dim_len * dim_len * b_index)
*/
struct wlr_color_transform_lut3d {
float *lut_3d;
size_t dim_len;
};
enum wlr_color_transform_type {
COLOR_TRANSFORM_INVERSE_EOTF,
COLOR_TRANSFORM_LCMS2,
COLOR_TRANSFORM_LUT_3X1D,
COLOR_TRANSFORM_PIPELINE,
COLOR_TRANSFORM_SRGB,
COLOR_TRANSFORM_LUT_3D,
};
struct wlr_color_transform {
@ -17,84 +33,7 @@ struct wlr_color_transform {
struct wlr_addon_set addons; // per-renderer helper state
enum wlr_color_transform_type type;
struct wlr_color_transform_lut3d lut3d;
};
struct wlr_color_transform_inverse_eotf {
struct wlr_color_transform base;
enum wlr_color_transfer_function tf;
};
/**
* The formula is approximated via three 1D look-up tables. The flat lut_3x1d
* array has a length of 3 * dim.
*
* The offset of a color value for a given channel and color index is:
*
* offset = channel_index * dim + color_index
*/
struct wlr_color_transform_lut_3x1d {
struct wlr_color_transform base;
uint16_t *lut_3x1d;
size_t dim;
};
struct wlr_color_transform_pipeline {
struct wlr_color_transform base;
struct wlr_color_transform **transforms;
size_t len;
};
void wlr_color_transform_init(struct wlr_color_transform *tr,
enum wlr_color_transform_type type);
/**
* Get a struct wlr_color_transform_lcms2 from a generic struct wlr_color_transform.
* Asserts that the base type is COLOR_TRANSFORM_LCMS2.
*/
struct wlr_color_transform_lcms2 *color_transform_lcms2_from_base(
struct wlr_color_transform *tr);
void color_transform_lcms2_finish(struct wlr_color_transform_lcms2 *tr);
/**
* Evaluate a LCMS2 color transform for a given RGB triplet.
*/
void color_transform_lcms2_eval(struct wlr_color_transform_lcms2 *tr,
float out[static 3], const float in[static 3]);
/**
* Gets a wlr_color_transform_inverse_eotf from a generic wlr_color_transform.
* Asserts that the base type is COLOR_TRANSFORM_INVERSE_EOTF
*/
struct wlr_color_transform_inverse_eotf *wlr_color_transform_inverse_eotf_from_base(
struct wlr_color_transform *tr);
/**
* Get a struct wlr_color_transform_lut_3x1d from a generic
* struct wlr_color_transform. Asserts that the base type is
* COLOR_TRANSFORM_LUT_3X1D.
*/
struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
struct wlr_color_transform *tr);
/**
* Obtain primaries values from a well-known primaries name.
*/
void wlr_color_primaries_from_named(struct wlr_color_primaries *out,
enum wlr_color_named_primaries named);
/**
* Compute the matrix to convert RGB color values to CIE 1931 XYZ.
*/
void wlr_color_primaries_to_xyz(const struct wlr_color_primaries *primaries, float matrix[static 9]);
/**
* Get default luminances for a transfer function.
*/
void wlr_color_transfer_function_get_default_luminance(enum wlr_color_transfer_function tf,
struct wlr_color_luminances *lum);
#endif

View file

@ -38,10 +38,6 @@ struct wlr_egl {
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT;
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT;
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;
PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR;
PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR;
PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID;
PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR;
} procs;
bool has_modifiers;
@ -109,12 +105,4 @@ bool wlr_egl_make_current(struct wlr_egl *egl, struct wlr_egl_context *save_cont
bool wlr_egl_unset_current(struct wlr_egl *egl);
EGLSyncKHR wlr_egl_create_sync(struct wlr_egl *egl, int fence_fd);
void wlr_egl_destroy_sync(struct wlr_egl *egl, EGLSyncKHR sync);
int wlr_egl_dup_fence_fd(struct wlr_egl *egl, EGLSyncKHR sync);
bool wlr_egl_wait_sync(struct wlr_egl *egl, EGLSyncKHR sync);
#endif

View file

@ -5,6 +5,7 @@
#include <GLES2/gl2ext.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <wlr/render/egl.h>
#include <wlr/render/gles2.h>
@ -137,8 +138,6 @@ struct wlr_gles2_render_pass {
float projection_matrix[9];
struct wlr_egl_context prev_ctx;
struct wlr_gles2_render_timer *timer;
struct wlr_drm_syncobj_timeline *signal_timeline;
uint64_t signal_point;
};
bool is_gles2_pixel_format_supported(const struct wlr_gles2_renderer *renderer,
@ -170,7 +169,6 @@ void push_gles2_debug_(struct wlr_gles2_renderer *renderer,
void pop_gles2_debug(struct wlr_gles2_renderer *renderer);
struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *buffer,
struct wlr_egl_context *prev_ctx, struct wlr_gles2_render_timer *timer,
struct wlr_drm_syncobj_timeline *signal_timeline, uint64_t signal_point);
struct wlr_egl_context *prev_ctx, struct wlr_gles2_render_timer *timer);
#endif

View file

@ -7,7 +7,6 @@
#include <vulkan/vulkan.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/render/wlr_texture.h>
#include <wlr/render/color.h>
#include <wlr/render/drm_format_set.h>
#include <wlr/render/interface.h>
#include <wlr/util/addon.h>
@ -41,7 +40,6 @@ struct wlr_vk_device {
int drm_fd;
bool sync_file_import_export;
bool implicit_sync_interop;
bool sampler_ycbcr_conversion;
@ -152,9 +150,6 @@ struct wlr_vk_pipeline_layout {
enum wlr_vk_texture_transform {
WLR_VK_TEXTURE_TRANSFORM_IDENTITY = 0,
WLR_VK_TEXTURE_TRANSFORM_SRGB = 1,
WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ = 2,
WLR_VK_TEXTURE_TRANSFORM_GAMMA22 = 3,
WLR_VK_TEXTURE_TRANSFORM_BT1886 = 4,
};
enum wlr_vk_shader_source {
@ -165,12 +160,8 @@ enum wlr_vk_shader_source {
// Constants used to pick the color transform for the blend-to-output
// fragment shader. Must match those in shaders/output.frag
enum wlr_vk_output_transform {
WLR_VK_OUTPUT_TRANSFORM_IDENTITY = 0,
WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB = 1,
WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ = 2,
WLR_VK_OUTPUT_TRANSFORM_LUT3D = 3,
WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22 = 4,
WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886 = 5,
WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB = 0,
WLR_VK_OUTPUT_TRANSFORM_LUT3D = 1,
};
struct wlr_vk_pipeline_key {
@ -199,24 +190,13 @@ struct wlr_vk_render_format_setup {
bool use_blending_buffer;
VkRenderPass render_pass;
VkPipeline output_pipe_identity;
VkPipeline output_pipe_srgb;
VkPipeline output_pipe_pq;
VkPipeline output_pipe_lut3d;
VkPipeline output_pipe_gamma22;
VkPipeline output_pipe_bt1886;
struct wlr_vk_renderer *renderer;
struct wl_list pipelines; // struct wlr_vk_pipeline.link
};
// Final output framebuffer and image view
struct wlr_vk_render_buffer_out {
VkImageView image_view;
VkFramebuffer framebuffer;
bool transitioned;
};
// Renderer-internal represenation of an wlr_buffer imported for rendering.
struct wlr_vk_render_buffer {
struct wlr_buffer *wlr_buffer;
@ -228,40 +208,36 @@ struct wlr_vk_render_buffer {
uint32_t mem_count;
VkImage image;
// Framebuffer and image view for rendering directly onto the buffer image,
// without any color transform.
struct {
struct wlr_vk_render_buffer_out out;
struct wlr_vk_render_format_setup *render_setup;
} linear;
// Framebuffer and image view for rendering directly onto the buffer image.
// This requires that the image support an _SRGB VkFormat, and does
// not work with color transforms.
struct {
struct wlr_vk_render_buffer_out out;
struct wlr_vk_render_format_setup *render_setup;
VkImageView image_view;
VkFramebuffer framebuffer;
bool transitioned;
} srgb;
// Framebuffer, image view, and blending image to render indirectly
// onto the buffer image. This works for general image types and permits
// color transforms.
struct {
struct wlr_vk_render_buffer_out out;
struct wlr_vk_render_format_setup *render_setup;
VkImageView image_view;
VkFramebuffer framebuffer;
bool transitioned;
VkImage blend_image;
VkImageView blend_image_view;
VkDeviceMemory blend_memory;
VkDescriptorSet blend_descriptor_set;
struct wlr_vk_descriptor_pool *blend_attachment_pool;
bool blend_transitioned;
} two_pass;
} plain;
};
bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
const struct wlr_dmabuf_attributes *dmabuf, bool srgb);
bool vulkan_setup_two_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer,
const struct wlr_dmabuf_attributes *dmabuf);
struct wlr_vk_command_buffer {
@ -277,8 +253,6 @@ struct wlr_vk_command_buffer {
// For DMA-BUF implicit sync interop, may be NULL
VkSemaphore binary_semaphore;
struct wl_array wait_semaphores; // VkSemaphore
};
#define VULKAN_COMMAND_BUFFERS_CAP 64
@ -357,15 +331,7 @@ struct wlr_vk_vert_pcr_data {
float uv_size[2];
};
struct wlr_vk_frag_texture_pcr_data {
float matrix[4][4]; // only a 3x3 subset is used
float alpha;
float luminance_multiplier;
};
struct wlr_vk_frag_output_pcr_data {
float matrix[4][4]; // only a 3x3 subset is used
float luminance_multiplier;
float lut_3d_offset;
float lut_3d_scale;
};
@ -373,7 +339,6 @@ struct wlr_vk_frag_output_pcr_data {
struct wlr_vk_texture_view {
struct wl_list link; // struct wlr_vk_texture.views
const struct wlr_vk_pipeline_layout *layout;
bool srgb;
VkDescriptorSet ds;
VkImageView image_view;
@ -388,7 +353,7 @@ struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout(
const struct wlr_vk_pipeline_layout_key *key);
struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(
struct wlr_vk_texture *texture,
const struct wlr_vk_pipeline_layout *layout, bool srgb);
const struct wlr_vk_pipeline_layout *layout);
// Creates a vulkan renderer for the given device.
struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev);
@ -402,34 +367,17 @@ VkCommandBuffer vulkan_record_stage_cb(struct wlr_vk_renderer *renderer);
// finished execution.
bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer);
struct wlr_vk_render_pass_texture {
struct wlr_vk_texture *texture;
struct wlr_drm_syncobj_timeline *wait_timeline;
uint64_t wait_point;
};
struct wlr_vk_render_pass {
struct wlr_render_pass base;
struct wlr_vk_renderer *renderer;
struct wlr_vk_render_buffer *render_buffer;
struct wlr_vk_render_buffer_out *render_buffer_out;
struct wlr_vk_render_format_setup *render_setup;
struct wlr_vk_command_buffer *command_buffer;
struct rect_union updated_region;
VkPipeline bound_pipeline;
float projection[9];
bool failed;
bool two_pass; // rendering via intermediate blending buffer
bool srgb_pathway; // if false, rendering via intermediate blending buffer
struct wlr_color_transform *color_transform;
bool has_primaries;
struct wlr_color_primaries primaries;
struct wlr_drm_syncobj_timeline *signal_timeline;
uint64_t signal_point;
struct wl_array textures; // struct wlr_vk_render_pass_texture
};
struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *renderer,
@ -471,10 +419,8 @@ bool vulkan_wait_command_buffer(struct wlr_vk_command_buffer *cb,
struct wlr_vk_renderer *renderer);
bool vulkan_sync_render_buffer(struct wlr_vk_renderer *renderer,
struct wlr_vk_render_buffer *render_buffer, struct wlr_vk_command_buffer *cb,
struct wlr_drm_syncobj_timeline *signal_timeline, uint64_t signal_point);
bool vulkan_sync_foreign_texture(struct wlr_vk_texture *texture,
int sync_file_fds[static WLR_DMABUF_MAX_PLANES]);
struct wlr_vk_render_buffer *render_buffer, struct wlr_vk_command_buffer *cb);
bool vulkan_sync_foreign_texture(struct wlr_vk_texture *texture);
bool vulkan_read_pixels(struct wlr_vk_renderer *vk_renderer,
VkFormat src_format, VkImage src_image,
@ -490,12 +436,13 @@ struct wlr_vk_texture {
VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
VkImage image;
const struct wlr_vk_format *format;
enum wlr_vk_texture_transform transform;
struct wlr_vk_command_buffer *last_used_cb; // to track when it can be destroyed
bool dmabuf_imported;
bool owned; // if dmabuf_imported: whether we have ownership of the image
bool transitioned; // if dma_imported: whether we transitioned it away from preinit
bool has_alpha; // whether the image is has alpha channel
bool using_mutable_srgb; // can be accessed through _SRGB format view
bool using_mutable_srgb; // is this accessed through _SRGB format view
struct wl_list foreign_link; // wlr_vk_renderer.foreign_textures
struct wl_list destroy_link; // wlr_vk_command_buffer.destroy_textures
struct wl_list link; // wlr_vk_renderer.textures
@ -503,8 +450,10 @@ struct wlr_vk_texture {
// If imported from a wlr_buffer
struct wlr_buffer *buffer;
struct wlr_addon buffer_addon;
// For DMA-BUF implicit sync interop
VkSemaphore foreign_semaphores[WLR_DMABUF_MAX_PLANES];
struct wl_list views; // struct wlr_vk_texture_view.link
struct wl_list views; // struct wlr_vk_texture_ds.link
};
struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture);
@ -536,7 +485,6 @@ struct wlr_vk_shared_buffer {
VkDeviceSize buf_size;
void *cpu_mapping;
struct wl_array allocs; // struct wlr_vk_allocation
int64_t last_used_ms;
};
// Suballocated range on a buffer.
@ -552,7 +500,6 @@ struct wlr_vk_color_transform {
struct wl_list link; // wlr_vk_renderer, list of all color transforms
struct {
size_t dim;
VkImage image;
VkImageView image_view;
VkDeviceMemory memory;

View file

@ -9,7 +9,7 @@
struct wlr_renderer *renderer_autocreate_with_drm_fd(int drm_fd);
/**
* Get the supported render formats. Buffers allocated with a format from this
* list may be used with wlr_renderer_begin_buffer_pass().
* list may be attached via wlr_renderer_begin_with_buffer.
*/
const struct wlr_drm_format_set *wlr_renderer_get_render_formats(
struct wlr_renderer *renderer);

View file

@ -50,6 +50,15 @@ struct wlr_dmabuf_buffer *dmabuf_buffer_create(
*/
bool dmabuf_buffer_drop(struct wlr_dmabuf_buffer *buffer);
/**
* Check whether a buffer is fully opaque.
*
* When true is returned, the buffer is guaranteed to be fully opaque, but the
* reverse is not true: false may be returned in cases where the buffer is fully
* opaque.
*/
bool buffer_is_opaque(struct wlr_buffer *buffer);
/**
* Creates a struct wlr_client_buffer from a given struct wlr_buffer by creating
* a texture from it, and copying its struct wl_resource.

View file

@ -0,0 +1,15 @@
#ifndef TYPES_WLR_MATRIX_H
#define TYPES_WLR_MATRIX_H
#include <wlr/types/wlr_matrix.h>
/**
* Writes a 2D orthographic projection matrix to mat of (width, height) with a
* specified wl_output_transform.
*
* Equivalent to glOrtho(0, width, 0, height, 1, -1) with the transform applied.
*/
void matrix_projection(float mat[static 9], int width, int height,
enum wl_output_transform transform);
#endif

View file

@ -8,8 +8,6 @@ void output_pending_resolution(struct wlr_output *output,
const struct wlr_output_state *state, int *width, int *height);
bool output_pending_enabled(struct wlr_output *output,
const struct wlr_output_state *state);
const struct wlr_output_image_description *output_pending_image_description(
struct wlr_output *output, const struct wlr_output_state *state);
bool output_pick_format(struct wlr_output *output,
const struct wlr_drm_format_set *display_formats,
@ -20,18 +18,11 @@ bool output_ensure_buffer(struct wlr_output *output,
bool output_cursor_set_texture(struct wlr_output_cursor *cursor,
struct wlr_texture *texture, bool own_texture, const struct wlr_fbox *src_box,
int dst_width, int dst_height, enum wl_output_transform transform,
int32_t hotspot_x, int32_t hotspot_y, struct wlr_drm_syncobj_timeline *wait_timeline,
uint64_t wait_point);
int32_t hotspot_x, int32_t hotspot_y);
void output_defer_present(struct wlr_output *output, struct wlr_output_event_present event);
bool output_prepare_commit(struct wlr_output *output, const struct wlr_output_state *state);
void output_apply_commit(struct wlr_output *output, const struct wlr_output_state *state);
void output_send_commit_event(struct wlr_output *output, const struct wlr_output_state *state);
void output_state_get_buffer_src_box(const struct wlr_output_state *state,
struct wlr_fbox *out);
void output_state_get_buffer_dst_box(const struct wlr_output_state *state,
struct wlr_box *out);
#endif

View file

@ -1,7 +1,7 @@
#ifndef TYPES_WLR_REGION_H
#define TYPES_WLR_REGION_H
#include <stdint.h>
#include <wlr/types/wlr_region.h>
struct wl_client;

View file

@ -5,8 +5,6 @@
struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node);
void scene_node_get_size(struct wlr_scene_node *node, int *width, int *height);
void scene_surface_set_clip(struct wlr_scene_surface *surface, struct wlr_box *clip);
#endif

View file

@ -1,14 +0,0 @@
#ifndef UTIL_MEM_H
#define UTIL_MEM_H
#include <stdbool.h>
#include <stddef.h>
/**
* Allocate a new block of memory and copy *src to it, then store the address
* of the new allocation in *out. Returns true if it worked, or false if
* allocation failed.
*/
bool memdup(void *out, const void *src, size_t size);
#endif // UTIL_MEM_H

View file

@ -4,8 +4,6 @@
#include <stdint.h>
#include <time.h>
static const long NSEC_PER_SEC = 1000000000;
/**
* Get the current time, in milliseconds.
*/

View file

@ -25,21 +25,10 @@ struct wlr_backend_output_state {
/**
* A backend provides a set of input and output devices.
*
* Buffer capabilities and features can change over the lifetime of a backend,
* for instance when a child backend is added to a multi-backend.
*/
struct wlr_backend {
const struct wlr_backend_impl *impl;
// Bitfield of supported buffer capabilities (see enum wlr_buffer_cap)
uint32_t buffer_caps;
struct {
// Whether wait/signal timelines are supported in output commits
bool timeline;
} features;
struct {
/** Raised when destroyed */
struct wl_signal destroy;
@ -65,12 +54,13 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_event_loop *loop,
struct wlr_session **session_ptr);
/**
* Start the backend. This may signal new_input or new_output immediately, but
* may also wait until the event loop is started. Returns false on failure.
* may also wait until the display's event loop begins. Returns false on
* failure.
*/
bool wlr_backend_start(struct wlr_backend *backend);
/**
* Destroy the backend and clean up all of its resources. Normally called
* automatically when the event loop is destroyed.
* automatically when the struct wl_display is destroyed.
*/
void wlr_backend_destroy(struct wlr_backend *backend);
/**

View file

@ -18,6 +18,7 @@ struct wlr_backend_impl {
bool (*start)(struct wlr_backend *backend);
void (*destroy)(struct wlr_backend *backend);
int (*get_drm_fd)(struct wlr_backend *backend);
uint32_t (*get_buffer_caps)(struct wlr_backend *backend);
bool (*test)(struct wlr_backend *backend,
const struct wlr_backend_output_state *states, size_t states_len);
bool (*commit)(struct wlr_backend *backend,

View file

@ -43,6 +43,11 @@ struct wlr_session {
*/
bool active;
/*
* 0 if virtual terminals are not supported
* i.e. seat != "seat0"
*/
unsigned vtnr;
char seat[256];
struct udev *udev;
@ -55,16 +60,13 @@ struct wlr_session {
struct wl_list devices; // wlr_device.link
struct wl_event_loop *event_loop;
struct wl_listener event_loop_destroy;
struct {
struct wl_signal active;
struct wl_signal add_drm_card; // struct wlr_session_add_event
struct wl_signal destroy;
} events;
struct {
struct wl_listener event_loop_destroy;
} WLR_PRIVATE;
};
struct wlr_session_add_event {

View file

@ -1,76 +1,19 @@
#ifndef WLR_CONFIG_H
#define WLR_CONFIG_H
/**
* Whether the DRM backend is compile-time enabled. Equivalent to the
* pkg-config "have_drm_backend" variable.
*
* Required for <wlr/backend/drm.h>.
*/
#mesondefine WLR_HAS_DRM_BACKEND
/**
* Whether the libinput backend is compile-time enabled. Equivalent to the
* pkg-config "have_libinput_backend" vartiable.
*
* Required for <wlr/backend/libinput.h>.
*/
#mesondefine WLR_HAS_LIBINPUT_BACKEND
/**
* Whether the X11 backend is compile-time enabled. Equivalent to the
* pkg-config "have_x11_backend" variable.
*
* Required for <wlr/backend/x11.h>.
*/
#mesondefine WLR_HAS_X11_BACKEND
/**
* Whether the GLES2 renderer is compile-time enabled. Equivalent to the
* pkg-config "have_gles2_renderer" variable.
*
* Required for <wlr/render/gles2.h>.
*/
#mesondefine WLR_HAS_GLES2_RENDERER
/**
* Whether the Vulkan renderer is compile-time enabled. Equivalent to the
* pkg-config "have_vulkan_renderer" variable.
*
* Required for <wlr/render/vulkan.h>.
*/
#mesondefine WLR_HAS_VULKAN_RENDERER
/**
* Whether the GBM allocator is compile-time enabled. Equivalent to the
* pkg-config "have_gbm_allocator" variable.
*/
#mesondefine WLR_HAS_GBM_ALLOCATOR
/**
* Whether the udmabuf allocator is compile-time enabled. Equivalent to the
* pkg-config "have_udmabuf_allocator" variable.
*/
#mesondefine WLR_HAS_UDMABUF_ALLOCATOR
/**
* Whether Xwayland support is compile-time enabled. Equivalent to the
* pkg-config "have_xwayland" variable.
*
* Required for <wlr/xwayland/>.
*/
#mesondefine WLR_HAS_XWAYLAND
/**
* Whether session support is compile-time enabled. Equivalent to the
* pkg-config "have_session" variable.
*
* Required for <wlr/backend/session.h>.
*/
#mesondefine WLR_HAS_SESSION
/**
* Whether traditional color management support is compile-time enabled.
* Equivalent to the pkg-config "have_color_management" variable.
*
* Required for ICC profile support in <wlr/render/color.h>.
*/
#mesondefine WLR_HAS_COLOR_MANAGEMENT
#endif

View file

@ -36,11 +36,6 @@ struct wlr_buffer_resource_interface {
void wlr_buffer_init(struct wlr_buffer *buffer,
const struct wlr_buffer_impl *impl, int width, int height);
/**
* Emit the destroy event and clean up common buffer state.
*/
void wlr_buffer_finish(struct wlr_buffer *buffer);
/**
* Allows the registration of a struct wl_resource implementation.
*

View file

@ -1,45 +0,0 @@
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif
#ifndef WLR_INTERFACES_WLR_EXT_IMAGE_CAPTURE_SOURCE_V1_H
#define WLR_INTERFACES_WLR_EXT_IMAGE_CAPTURE_SOURCE_V1_H
#include <wayland-server-core.h>
#include <wlr/types/wlr_ext_image_capture_source_v1.h>
struct wlr_ext_image_copy_capture_frame_v1;
struct wlr_swapchain;
struct wlr_renderer;
struct wlr_seat;
struct wlr_ext_image_capture_source_v1_interface {
// TODO: drop with_cursors flag
void (*start)(struct wlr_ext_image_capture_source_v1 *source, bool with_cursors);
void (*stop)(struct wlr_ext_image_capture_source_v1 *source);
void (*schedule_frame)(struct wlr_ext_image_capture_source_v1 *source);
void (*copy_frame)(struct wlr_ext_image_capture_source_v1 *source,
struct wlr_ext_image_copy_capture_frame_v1 *dst_frame,
struct wlr_ext_image_capture_source_v1_frame_event *frame_event);
struct wlr_ext_image_capture_source_v1_cursor *(*get_pointer_cursor)(
struct wlr_ext_image_capture_source_v1 *source, struct wlr_seat *seat);
};
void wlr_ext_image_capture_source_v1_init(struct wlr_ext_image_capture_source_v1 *source,
const struct wlr_ext_image_capture_source_v1_interface *impl);
void wlr_ext_image_capture_source_v1_finish(struct wlr_ext_image_capture_source_v1 *source);
bool wlr_ext_image_capture_source_v1_create_resource(struct wlr_ext_image_capture_source_v1 *source,
struct wl_client *client, uint32_t new_id);
bool wlr_ext_image_capture_source_v1_set_constraints_from_swapchain(
struct wlr_ext_image_capture_source_v1 *source,
struct wlr_swapchain *swapchain, struct wlr_renderer *renderer);
void wlr_ext_image_capture_source_v1_cursor_init(struct wlr_ext_image_capture_source_v1_cursor *source_cursor,
const struct wlr_ext_image_capture_source_v1_interface *impl);
void wlr_ext_image_capture_source_v1_cursor_finish(struct wlr_ext_image_capture_source_v1_cursor *source_cursor);
#endif

View file

@ -108,10 +108,6 @@ struct wlr_output_impl {
void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend,
const struct wlr_output_impl *impl, struct wl_event_loop *event_loop,
const struct wlr_output_state *state);
/**
* Emit the destroy event and clean up common output state.
*/
void wlr_output_finish(struct wlr_output *output);
/**
* Notify compositors that they need to submit a new frame in order to apply
* output changes.

View file

@ -19,7 +19,4 @@ void wlr_pointer_init(struct wlr_pointer *pointer,
const struct wlr_pointer_impl *impl, const char *name);
void wlr_pointer_finish(struct wlr_pointer *pointer);
void wlr_pointer_notify_button(struct wlr_pointer *pointer,
struct wlr_pointer_button_event *event);
#endif

View file

@ -10,100 +10,8 @@
#define WLR_RENDER_COLOR_H
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
/**
* Well-known color primaries.
*/
enum wlr_color_named_primaries {
WLR_COLOR_NAMED_PRIMARIES_SRGB = 1 << 0,
WLR_COLOR_NAMED_PRIMARIES_BT2020 = 1 << 1,
};
/**
* Well-known color transfer functions.
*/
enum wlr_color_transfer_function {
WLR_COLOR_TRANSFER_FUNCTION_SRGB = 1 << 0,
WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ = 1 << 1,
WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR = 1 << 2,
WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 = 1 << 3,
WLR_COLOR_TRANSFER_FUNCTION_BT1886 = 1 << 4,
};
/**
* Specifies alpha blending modes. Note that premultiplied_electrical
* is the default, so there is no "none" or "unset" value.
*/
enum wlr_alpha_mode {
WLR_COLOR_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL,
WLR_COLOR_ALPHA_MODE_PREMULTIPLIED_OPTICAL,
WLR_COLOR_ALPHA_MODE_STRAIGHT,
};
/**
* Well-known color encodings, each representing a set of matrix coefficients
* used to convert that particular YCbCr encoding to RGB. NONE means the
* value is unset or unknown.
*/
enum wlr_color_encoding {
WLR_COLOR_ENCODING_NONE,
WLR_COLOR_ENCODING_IDENTITY,
WLR_COLOR_ENCODING_BT709,
WLR_COLOR_ENCODING_FCC,
WLR_COLOR_ENCODING_BT601,
WLR_COLOR_ENCODING_SMPTE240,
WLR_COLOR_ENCODING_BT2020,
WLR_COLOR_ENCODING_BT2020_CL,
WLR_COLOR_ENCODING_ICTCP,
};
/**
* Specifies whether a particular color-encoding uses full- or limited-range
* values. NONE means the value is unset or unknown.
*/
enum wlr_color_range {
WLR_COLOR_RANGE_NONE,
WLR_COLOR_RANGE_LIMITED,
WLR_COLOR_RANGE_FULL,
};
/**
* Chroma sample locations, corresponding to Chroma420SampleLocType code
* points in H.273. NONE means the value is unset or unknown.
*/
enum wlr_color_chroma_location {
WLR_COLOR_CHROMA_LOCATION_NONE,
WLR_COLOR_CHROMA_LOCATION_TYPE0,
WLR_COLOR_CHROMA_LOCATION_TYPE1,
WLR_COLOR_CHROMA_LOCATION_TYPE2,
WLR_COLOR_CHROMA_LOCATION_TYPE3,
WLR_COLOR_CHROMA_LOCATION_TYPE4,
WLR_COLOR_CHROMA_LOCATION_TYPE5,
};
/**
* CIE 1931 xy chromaticity coordinates.
*/
struct wlr_color_cie1931_xy {
float x, y;
};
/**
* Color primaries and white point describing a color volume.
*/
struct wlr_color_primaries {
struct wlr_color_cie1931_xy red, green, blue, white;
};
/**
* Luminance range and reference white luminance level, in cd/m².
*/
struct wlr_color_luminances {
float min, max, reference;
};
/**
* A color transformation formula, which maps a linear color space with
* sRGB primaries to an output color space.
@ -128,30 +36,15 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
const void *data, size_t size);
/**
* Initialize a color transformation to apply EOTF¹ encoding. Returns
* NULL on failure.
* Initialize a color transformation to apply sRGB encoding.
* Returns NULL on failure.
*/
struct wlr_color_transform *wlr_color_transform_init_linear_to_inverse_eotf(
enum wlr_color_transfer_function tf);
/**
* Initialize a color transformation to apply three 1D look-up tables. dim
* is the number of elements in each individual LUT. Returns NULL on failure.
*/
struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
const uint16_t *r, const uint16_t *g, const uint16_t *b);
/**
* Initialize a color transformation to apply a sequence of color transforms
* one after another.
*/
struct wlr_color_transform *wlr_color_transform_init_pipeline(
struct wlr_color_transform **transforms, size_t len);
struct wlr_color_transform *wlr_color_transform_init_srgb(void);
/**
* Increase the reference count of the color transform by 1.
*/
struct wlr_color_transform *wlr_color_transform_ref(struct wlr_color_transform *tr);
void wlr_color_transform_ref(struct wlr_color_transform *tr);
/**
* Reduce the reference count of the color transform by 1; freeing it and
@ -159,10 +52,4 @@ struct wlr_color_transform *wlr_color_transform_ref(struct wlr_color_transform *
*/
void wlr_color_transform_unref(struct wlr_color_transform *tr);
/**
* Evaluate a color transform for a given RGB triplet.
*/
void wlr_color_transform_eval(struct wlr_color_transform *tr,
float out[static 3], const float in[static 3]);
#endif

View file

@ -69,9 +69,6 @@ void wlr_drm_format_set_finish(struct wlr_drm_format_set *set);
const struct wlr_drm_format *wlr_drm_format_set_get(
const struct wlr_drm_format_set *set, uint32_t format);
bool wlr_drm_format_set_remove(struct wlr_drm_format_set *set, uint32_t format,
uint64_t modifier);
bool wlr_drm_format_set_has(const struct wlr_drm_format_set *set,
uint32_t format, uint64_t modifier);

View file

@ -4,7 +4,6 @@
#include <stdbool.h>
#include <stdint.h>
#include <wayland-server-core.h>
#include <wlr/util/addon.h>
/**
* A synchronization timeline.
@ -30,24 +29,20 @@ struct wlr_drm_syncobj_timeline {
int drm_fd;
uint32_t handle;
struct wlr_addon_set addons;
// private state
struct {
size_t n_refs;
} WLR_PRIVATE;
size_t n_refs;
};
struct wlr_drm_syncobj_timeline_waiter;
typedef void (*wlr_drm_syncobj_timeline_ready_callback)(
struct wlr_drm_syncobj_timeline_waiter *waiter);
struct wlr_drm_syncobj_timeline_waiter {
struct {
int ev_fd;
struct wl_event_source *event_source;
wlr_drm_syncobj_timeline_ready_callback callback;
} WLR_PRIVATE;
struct wl_signal ready;
} events;
// private state
int ev_fd;
struct wl_event_source *event_source;
};
/**
@ -67,17 +62,6 @@ struct wlr_drm_syncobj_timeline *wlr_drm_syncobj_timeline_ref(struct wlr_drm_syn
* Unreference a synchronization timeline.
*/
void wlr_drm_syncobj_timeline_unref(struct wlr_drm_syncobj_timeline *timeline);
/**
* Export a drm_syncobj FD from a timeline.
*/
int wlr_drm_syncobj_timeline_export(struct wlr_drm_syncobj_timeline *timeline);
/**
* Transfer a point from a timeline to another.
*
* Both timelines must have been created with the same DRM FD.
*/
bool wlr_drm_syncobj_timeline_transfer(struct wlr_drm_syncobj_timeline *dst,
uint64_t dst_point, struct wlr_drm_syncobj_timeline *src, uint64_t src_point);
/**
* Check if a timeline point has been signalled or has materialized.
*
@ -94,12 +78,10 @@ bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline,
* Asynchronously wait for a timeline point.
*
* 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.
*/
bool wlr_drm_syncobj_timeline_waiter_init(struct wlr_drm_syncobj_timeline_waiter *waiter,
struct wlr_drm_syncobj_timeline *timeline, uint64_t point, uint32_t flags,
struct wl_event_loop *loop, wlr_drm_syncobj_timeline_ready_callback callback);
struct wl_event_loop *loop);
/**
* Cancel a timeline waiter.
*/

View file

@ -12,7 +12,6 @@
#include <pixman.h>
#include <stdint.h>
#include <wayland-server-core.h>
#include <wlr/render/color.h>
#include <wlr/util/box.h>
struct wlr_renderer;
@ -31,23 +30,9 @@ struct wlr_render_timer;
struct wlr_buffer_pass_options {
/* Timer to measure the duration of the render pass */
struct wlr_render_timer *timer;
/* Color transform to apply to the output of the render pass.
* Leave NULL to indicate the default transform (Gamma 2.2 encoding for
* sRGB monitors) */
/* Color transform to apply to the output of the render pass,
* leave NULL to indicate sRGB/no custom transform */
struct wlr_color_transform *color_transform;
/** Primaries describing the color volume of the destination buffer */
const struct wlr_color_primaries *primaries;
/* Signal a timeline synchronization point when the render pass completes.
*
* When a compositor provides a signal timeline, the renderer may skip
* implicit signal synchronization.
*
* Support for this feature is advertised by features.timeline in
* struct wlr_renderer.
*/
struct wlr_drm_syncobj_timeline *signal_timeline;
uint64_t signal_point;
};
/**
@ -103,21 +88,6 @@ struct wlr_render_texture_options {
enum wlr_scale_filter_mode filter_mode;
/* Blend mode */
enum wlr_render_blend_mode blend_mode;
/* Transfer function the source texture is encoded with */
enum wlr_color_transfer_function transfer_function;
/* Primaries describing the color volume of the source texture */
const struct wlr_color_primaries *primaries;
/* Wait for a timeline synchronization point before texturing.
*
* When a compositor provides a wait timeline, the renderer may skip
* implicit wait synchronization.
*
* Support for this feature is advertised by features.timeline in
* struct wlr_renderer.
*/
struct wlr_drm_syncobj_timeline *wait_timeline;
uint64_t wait_point;
};
/**

View file

@ -10,10 +10,9 @@
struct wlr_swapchain_slot {
struct wlr_buffer *buffer;
bool acquired; // waiting for release
int age;
struct {
struct wl_listener release;
} WLR_PRIVATE;
struct wl_listener release;
};
struct wlr_swapchain {
@ -24,9 +23,7 @@ struct wlr_swapchain {
struct wlr_swapchain_slot slots[WLR_SWAPCHAIN_CAP];
struct {
struct wl_listener allocator_destroy;
} WLR_PRIVATE;
struct wl_listener allocator_destroy;
};
struct wlr_swapchain *wlr_swapchain_create(
@ -39,12 +36,21 @@ void wlr_swapchain_destroy(struct wlr_swapchain *swapchain);
* The returned buffer is locked. When the caller is done with it, they must
* unlock it by calling wlr_buffer_unlock.
*/
struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain);
struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain,
int *age);
/**
* Returns true if this buffer has been created by this swapchain, and false
* otherwise.
*/
bool wlr_swapchain_has_buffer(struct wlr_swapchain *swapchain,
struct wlr_buffer *buffer);
/**
* Mark the buffer as submitted for presentation. This needs to be called by
* swap chain users on frame boundaries.
*
* If the buffer hasn't been created via the swap chain, the call is ignored.
*/
void wlr_swapchain_set_buffer_submitted(struct wlr_swapchain *swapchain,
struct wlr_buffer *buffer);
#endif

View file

@ -41,25 +41,15 @@ struct wlr_renderer {
} events;
struct {
/**
* Whether color transforms are supported for input textures
*/
bool input_color_transform;
/**
* Does the renderer support color transforms on its output?
*/
bool output_color_transform;
/**
* Whether wait/signal timelines are supported.
*
* See struct wlr_drm_syncobj_timeline.
*/
bool timeline;
} features;
struct {
const struct wlr_renderer_impl *impl;
} WLR_PRIVATE;
// private state
const struct wlr_renderer_impl *impl;
};
/**

View file

@ -20,9 +20,9 @@ struct wlr_alpha_modifier_surface_v1_state {
struct wlr_alpha_modifier_v1 {
struct wl_global *global;
struct {
struct wl_listener display_destroy;
} WLR_PRIVATE;
// private state
struct wl_listener display_destroy;
};
struct wlr_alpha_modifier_v1 *wlr_alpha_modifier_v1_create(struct wl_display *display);

View file

@ -17,15 +17,11 @@
struct wlr_buffer;
struct wlr_renderer;
/**
* Shared-memory attributes for a buffer.
*/
struct wlr_shm_attributes {
int fd;
uint32_t format; // FourCC code, see DRM_FORMAT_* in <drm_fourcc.h>
int width, height;
int stride; // Number of bytes between consecutive pixel lines
off_t offset; // Offset in bytes of the first pixel in FD
uint32_t format;
int width, height, stride;
off_t offset;
};
/**
@ -109,15 +105,6 @@ bool wlr_buffer_get_shm(struct wlr_buffer *buffer,
*/
struct wlr_buffer *wlr_buffer_try_from_resource(struct wl_resource *resource);
/**
* Check whether a buffer is fully opaque.
*
* When true is returned, the buffer is guaranteed to be fully opaque, but the
* reverse is not true: false may be returned in cases where the buffer is fully
* opaque.
*/
bool wlr_buffer_is_opaque(struct wlr_buffer *buffer);
/**
* Buffer data pointer access flags.
*/
@ -143,12 +130,6 @@ enum wlr_buffer_data_ptr_access_flag {
*/
bool wlr_buffer_begin_data_ptr_access(struct wlr_buffer *buffer, uint32_t flags,
void **data, uint32_t *format, size_t *stride);
/**
* Indicate that a pointer to a buffer's underlying memory will no longer be
* used.
*
* This function must be called after wlr_buffer_begin_data_ptr_access().
*/
void wlr_buffer_end_data_ptr_access(struct wlr_buffer *buffer);
/**
@ -167,12 +148,12 @@ struct wlr_client_buffer {
*/
struct wlr_buffer *source;
struct {
struct wl_listener source_destroy;
struct wl_listener renderer_destroy;
// private state
size_t n_ignore_locks;
} WLR_PRIVATE;
struct wl_listener source_destroy;
struct wl_listener renderer_destroy;
size_t n_ignore_locks;
};
/**
@ -181,29 +162,4 @@ struct wlr_client_buffer {
*/
struct wlr_client_buffer *wlr_client_buffer_get(struct wlr_buffer *buffer);
/**
* A single-pixel buffer. Used by clients to draw solid-color rectangles.
*/
struct wlr_single_pixel_buffer_v1 {
struct wlr_buffer base;
// Full-scale for each component is UINT32_MAX
uint32_t r, g, b, a;
struct {
struct wl_resource *resource;
struct wl_listener release;
// Packed little-endian DRM_FORMAT_ARGB8888. Used for data_ptr_access
uint8_t argb8888[4];
} WLR_PRIVATE;
};
/**
* If the wlr_buffer is a wlr_single_pixel_buffer_v1 then unwrap it.
* Otherwise, returns NULL.
*/
struct wlr_single_pixel_buffer_v1 *wlr_single_pixel_buffer_v1_try_from_buffer(
struct wlr_buffer *buffer);
#endif

View file

@ -1,122 +0,0 @@
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif
#ifndef WLR_TYPES_WLR_COLOR_MANAGEMENT_V1_H
#define WLR_TYPES_WLR_COLOR_MANAGEMENT_V1_H
#include <wayland-server-core.h>
#include <wayland-protocols/color-management-v1-enum.h>
#include <wlr/render/color.h>
struct wlr_surface;
struct wlr_image_description_v1_data {
uint32_t tf_named; // enum wp_color_manager_v1_transfer_function, zero if unset
uint32_t primaries_named; // enum wp_color_manager_v1_primaries, zero if unset
bool has_mastering_display_primaries;
struct wlr_color_primaries mastering_display_primaries;
bool has_mastering_luminance;
struct {
float min, max; // cd/m²
} mastering_luminance;
uint32_t max_cll, max_fall; // cd/m², zero if unset
};
struct wlr_color_manager_v1_features {
bool icc_v2_v4;
bool parametric;
bool set_primaries;
bool set_tf_power;
bool set_luminances;
bool set_mastering_display_primaries;
bool extended_target_volume;
bool windows_scrgb;
};
struct wlr_color_manager_v1_options {
struct wlr_color_manager_v1_features features;
const enum wp_color_manager_v1_render_intent *render_intents;
size_t render_intents_len;
const enum wp_color_manager_v1_transfer_function *transfer_functions;
size_t transfer_functions_len;
const enum wp_color_manager_v1_primaries *primaries;
size_t primaries_len;
};
struct wlr_color_manager_v1 {
struct wl_global *global;
struct {
struct wl_signal destroy;
} events;
struct {
struct wlr_color_manager_v1_features features;
enum wp_color_manager_v1_render_intent *render_intents;
size_t render_intents_len;
enum wp_color_manager_v1_transfer_function *transfer_functions;
size_t transfer_functions_len;
enum wp_color_manager_v1_primaries *primaries;
size_t primaries_len;
struct wl_list outputs; // wlr_color_management_output_v1.link
struct wl_list surface_feedbacks; // wlr_color_management_surface_feedback_v1.link
uint32_t last_image_desc_identity;
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
struct wlr_color_manager_v1 *wlr_color_manager_v1_create(struct wl_display *display,
uint32_t version, const struct wlr_color_manager_v1_options *options);
const struct wlr_image_description_v1_data *
wlr_surface_get_image_description_v1_data(struct wlr_surface *surface);
void wlr_color_manager_v1_set_surface_preferred_image_description(
struct wlr_color_manager_v1 *manager, struct wlr_surface *surface,
const struct wlr_image_description_v1_data *data);
/**
* Convert a protocol transfer function to enum wlr_color_transfer_function.
* Aborts if there is no matching wlroots entry.
*/
enum wlr_color_transfer_function
wlr_color_manager_v1_transfer_function_to_wlr(enum wp_color_manager_v1_transfer_function tf);
/**
* Convert an enum wlr_color_transfer_function value into a protocol transfer function.
*/
enum wp_color_manager_v1_transfer_function
wlr_color_manager_v1_transfer_function_from_wlr(enum wlr_color_transfer_function tf);
/**
* Convert a protocol named primaries to enum wlr_color_named_primaries.
* Aborts if there is no matching wlroots entry.
*/
enum wlr_color_named_primaries
wlr_color_manager_v1_primaries_to_wlr(enum wp_color_manager_v1_primaries primaries);
/**
* Convert an enum wlr_color_named_primaries value into protocol primaries.
*/
enum wp_color_manager_v1_primaries
wlr_color_manager_v1_primaries_from_wlr(enum wlr_color_named_primaries primaries);
#endif

View file

@ -1,93 +0,0 @@
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif
#ifndef WLR_TYPES_WLR_COLOR_REPRESENTATION_V1_H
#define WLR_TYPES_WLR_COLOR_REPRESENTATION_V1_H
#include <wayland-server-core.h>
#include <wayland-protocols/color-representation-v1-enum.h>
#include <wlr/render/color.h>
struct wlr_surface;
// Supported coefficients and range are always paired together
struct wlr_color_representation_v1_coeffs_and_range {
enum wp_color_representation_surface_v1_coefficients coeffs;
enum wp_color_representation_surface_v1_range range;
};
struct wlr_color_representation_manager_v1 {
struct wl_global *global;
struct {
// Manager is being destroyed
struct wl_signal destroy;
} events;
struct {
enum wp_color_representation_surface_v1_alpha_mode
*supported_alpha_modes;
size_t supported_alpha_modes_len;
struct wlr_color_representation_v1_coeffs_and_range
*supported_coeffs_and_ranges;
size_t supported_coeffs_and_ranges_len;
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
// Options used when initialising a wlr_color_representation_manager_v1
struct wlr_color_representation_v1_options {
enum wp_color_representation_surface_v1_alpha_mode
*supported_alpha_modes;
size_t supported_alpha_modes_len;
const struct wlr_color_representation_v1_coeffs_and_range
*supported_coeffs_and_ranges;
size_t supported_coeffs_and_ranges_len;
};
struct wlr_color_representation_manager_v1 *wlr_color_representation_manager_v1_create(
struct wl_display *display, uint32_t version,
const struct wlr_color_representation_v1_options *options);
// This is all the color-representation state which can be attached to a
// surface, double-buffered and made current on commit
struct wlr_color_representation_v1_surface_state {
// The enum premultiplied_electrical has value zero and is defined
// to be the default if unspecified.
enum wp_color_representation_surface_v1_alpha_mode alpha_mode;
// If zero then indicates unset, otherwise values correspond to
// enum wp_color_representation_surface_v1_coefficients
uint32_t coefficients;
// If zero then indicates unset, otherwise values correspond to
// enum wp_color_representation_surface_v1_range
uint32_t range;
// If zero then indicates unset, otherwise values correspond to
// enum wp_color_representation_surface_v1_chroma_location
uint32_t chroma_location;
};
// Get the current color representation state committed to a surface
const struct wlr_color_representation_v1_surface_state *wlr_color_representation_v1_get_surface_state(
struct wlr_surface *surface);
enum wlr_alpha_mode wlr_color_representation_v1_alpha_mode_to_wlr(
enum wp_color_representation_surface_v1_alpha_mode wp_val);
enum wlr_color_encoding wlr_color_representation_v1_color_encoding_to_wlr(
enum wp_color_representation_surface_v1_coefficients wp_val);
enum wlr_color_range wlr_color_representation_v1_color_range_to_wlr(
enum wp_color_representation_surface_v1_range wp_val);
enum wlr_color_chroma_location wlr_color_representation_v1_chroma_location_to_wlr(
enum wp_color_representation_surface_v1_chroma_location wp_val);
#endif // WLR_TYPES_WLR_COLOR_REPRESENTATION_V1_H

View file

@ -14,11 +14,10 @@
#include <stdint.h>
#include <time.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_output.h>
#include <wlr/util/addon.h>
#include <wlr/util/box.h>
struct wlr_surface;
enum wlr_surface_state_field {
WLR_SURFACE_STATE_BUFFER = 1 << 0,
WLR_SURFACE_STATE_SURFACE_DAMAGE = 1 << 1,
@ -98,13 +97,6 @@ struct wlr_surface_role {
* such object exists.
*/
void (*commit)(struct wlr_surface *surface);
/**
* Called when the surface is mapped. May be NULL.
*
* If the role is represented by an object, this is only called if
* such object exists.
*/
void (*map)(struct wlr_surface *surface);
/**
* Called when the surface is unmapped. May be NULL.
*
@ -123,11 +115,8 @@ struct wlr_surface_output {
struct wlr_output *output;
struct wl_list link; // wlr_surface.current_outputs
struct {
struct wl_listener bind;
struct wl_listener destroy;
} WLR_PRIVATE;
struct wl_listener bind;
struct wl_listener destroy;
};
struct wlr_surface {
@ -191,47 +180,28 @@ struct wlr_surface {
struct wl_resource *role_resource;
struct {
/**
* Signals that the client has sent a wl_surface.commit request.
*
* The state to be committed can be accessed in wlr_surface.pending.
*
* The commit may not be applied immediately, in which case it's marked
* as "cached" and put into a queue. See wlr_surface_lock_pending().
*/
struct wl_signal client_commit;
/**
* Signals that a commit has been applied.
*
* The new state can be accessed in wlr_surface.current.
*/
struct wl_signal commit;
/**
* Signals that the surface has a non-null buffer committed and is
* ready to be displayed.
* The `map` event signals that the surface has a non-null buffer
* committed and is ready to be displayed.
*/
struct wl_signal map;
/**
* Signals that the surface shouldn't be displayed anymore. This can
* happen when a null buffer is committed, the associated role object
* is destroyed, or when the role-specific conditions for the surface
* to be mapped no longer apply.
* The `unmap` event signals that the surface shouldn't be displayed
* anymore. This can happen when a null buffer is committed,
* the associated role object is destroyed, or when the role-specific
* conditions for the surface to be mapped no longer apply.
*/
struct wl_signal unmap;
/**
* Signals that a new child sub-surface has been added.
*
* Note: unlike other new_* signals, new_subsurface is emitted when
* the subsurface is added to the parent surface's current state,
* not when the object is created.
*/
struct wl_signal new_subsurface; // struct wlr_subsurface
/**
* Signals that the surface is being destroyed.
*/
struct wl_signal destroy;
} events;
@ -240,33 +210,33 @@ struct wlr_surface {
struct wlr_addon_set addons;
void *data;
// private state
struct wl_listener role_resource_destroy;
struct {
struct wl_listener role_resource_destroy;
int32_t scale;
enum wl_output_transform transform;
int width, height;
int buffer_width, buffer_height;
} previous;
struct {
int32_t scale;
enum wl_output_transform transform;
int width, height;
int buffer_width, buffer_height;
} previous;
bool unmap_commit;
bool unmap_commit;
bool opaque;
bool opaque;
bool handling_commit;
bool pending_rejected;
bool handling_commit;
bool pending_rejected;
int32_t preferred_buffer_scale;
bool preferred_buffer_transform_sent;
enum wl_output_transform preferred_buffer_transform;
int32_t preferred_buffer_scale;
bool preferred_buffer_transform_sent;
enum wl_output_transform preferred_buffer_transform;
struct wl_list synced; // wlr_surface_synced.link
size_t synced_len;
struct wl_list synced; // wlr_surface_synced.link
size_t synced_len;
struct wl_resource *pending_buffer_resource;
struct wl_listener pending_buffer_resource_destroy;
} WLR_PRIVATE;
struct wl_resource *pending_buffer_resource;
struct wl_listener pending_buffer_resource_destroy;
};
struct wlr_renderer;
@ -275,15 +245,13 @@ struct wlr_compositor {
struct wl_global *global;
struct wlr_renderer *renderer; // may be NULL
struct wl_listener display_destroy;
struct wl_listener renderer_destroy;
struct {
struct wl_signal new_surface;
struct wl_signal destroy;
} events;
struct {
struct wl_listener display_destroy;
struct wl_listener renderer_destroy;
} WLR_PRIVATE;
};
typedef void (*wlr_surface_iterator_func_t)(struct wlr_surface *surface,
@ -413,7 +381,7 @@ void wlr_surface_send_frame_done(struct wlr_surface *surface,
* surface coordinates.
* X and y may be negative, if there are subsurfaces with negative position.
*/
void wlr_surface_get_extents(struct wlr_surface *surface, struct wlr_box *box);
void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box);
/**
* Get the struct wlr_surface corresponding to a wl_surface resource.
@ -485,8 +453,6 @@ void wlr_surface_set_preferred_buffer_scale(struct wlr_surface *surface,
void wlr_surface_set_preferred_buffer_transform(struct wlr_surface *surface,
enum wl_output_transform transform);
struct wlr_surface_synced;
/**
* Implementation for struct wlr_surface_synced.
*
@ -503,11 +469,6 @@ struct wlr_surface_synced_impl {
void (*finish_state)(void *state);
// Move a state. If NULL, memcpy() is used.
void (*move_state)(void *dst, void *src);
// Called when the state is committed. If NULL, this is a no-op.
// If an object is a surface role object which has state synchronized with
// the surface state, the role commit hook should be preferred over this.
void (*commit)(struct wlr_surface_synced *synced);
};
/**

View file

@ -10,7 +10,7 @@
#define WLR_TYPES_WLR_CONTENT_TYPE_V1_H
#include <wayland-server-core.h>
#include <wayland-protocols/content-type-v1-enum.h>
#include "content-type-v1-protocol.h"
struct wlr_surface;
@ -23,9 +23,9 @@ struct wlr_content_type_manager_v1 {
void *data;
struct {
struct wl_listener display_destroy;
} WLR_PRIVATE;
// private state
struct wl_listener display_destroy;
};
struct wlr_content_type_manager_v1 *wlr_content_type_manager_v1_create(

View file

@ -11,9 +11,9 @@
#include <wayland-server-core.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
struct wlr_input_device;
struct wlr_surface;
struct wlr_xcursor_manager;
/**

View file

@ -10,7 +10,7 @@
#define WLR_TYPES_WLR_CURSOR_SHAPE_V1_H
#include <wayland-server-core.h>
#include <wayland-protocols/cursor-shape-v1-enum.h>
#include "cursor-shape-v1-protocol.h"
/**
* Manager for the cursor-shape-v1 protocol.
@ -28,9 +28,9 @@ struct wlr_cursor_shape_manager_v1 {
void *data;
struct {
struct wl_listener display_destroy;
} WLR_PRIVATE;
// private state
struct wl_listener display_destroy;
};
enum wlr_cursor_shape_manager_v1_device_type {

View file

@ -15,27 +15,32 @@
#include <pixman.h>
#include <wayland-server-core.h>
/* For triple buffering, a history of two frames is required. */
#define WLR_DAMAGE_RING_PREVIOUS_LEN 2
struct wlr_box;
struct wlr_damage_ring_buffer {
struct wlr_buffer *buffer;
struct wl_listener destroy;
pixman_region32_t damage;
struct wlr_damage_ring *ring;
struct wl_list link; // wlr_damage_ring.buffers
struct {
struct wl_listener destroy;
} WLR_PRIVATE;
};
struct wlr_damage_ring {
int32_t width, height;
// Difference between the current buffer and the previous one
pixman_region32_t current;
struct {
struct wl_list buffers; // wlr_damage_ring_buffer.link
} WLR_PRIVATE;
// private state
pixman_region32_t previous[WLR_DAMAGE_RING_PREVIOUS_LEN];
size_t previous_idx;
struct wl_list buffers; // wlr_damage_ring_buffer.link
};
void wlr_damage_ring_init(struct wlr_damage_ring *ring);
@ -43,17 +48,30 @@ void wlr_damage_ring_init(struct wlr_damage_ring *ring);
void wlr_damage_ring_finish(struct wlr_damage_ring *ring);
/**
* Add a region to the current damage. The region must be in the buffer-local
* coordinate space.
* Set ring bounds and damage the ring fully.
*
* Next time damage will be added, it will be cropped to the ring bounds.
* If at least one of the dimensions is 0, bounds are removed.
*
* By default, a damage ring doesn't have bounds.
*/
void wlr_damage_ring_add(struct wlr_damage_ring *ring,
void wlr_damage_ring_set_bounds(struct wlr_damage_ring *ring,
int32_t width, int32_t height);
/**
* Add a region to the current damage.
*
* Returns true if the region intersects the ring bounds, false otherwise.
*/
bool wlr_damage_ring_add(struct wlr_damage_ring *ring,
const pixman_region32_t *damage);
/**
* Add a box to the current damage. The box must be in the buffer-local
* coordinate space.
* Add a box to the current damage.
*
* Returns true if the box intersects the ring bounds, false otherwise.
*/
void wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
bool wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
const struct wlr_box *box);
/**
@ -61,6 +79,20 @@ void wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
*/
void wlr_damage_ring_add_whole(struct wlr_damage_ring *ring);
/**
* Rotate the damage ring. This needs to be called after using the accumulated
* damage, e.g. after rendering to an output's back buffer.
*/
void wlr_damage_ring_rotate(struct wlr_damage_ring *ring);
/**
* Get accumulated damage, which is the difference between the current buffer
* and the buffer with age of buffer_age; in context of rendering, this is
* the region that needs to be redrawn.
*/
void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring,
int buffer_age, pixman_region32_t *damage);
/**
* Get accumulated buffer damage and rotate the damage ring.
*
@ -70,8 +102,6 @@ void wlr_damage_ring_add_whole(struct wlr_damage_ring *ring);
*
* Users should damage the ring if an error occurs while rendering or
* submitting the new buffer to the backend.
*
* The returned damage will be in the buffer-local coordinate space.
*/
void wlr_damage_ring_rotate_buffer(struct wlr_damage_ring *ring,
struct wlr_buffer *buffer, pixman_region32_t *damage);

View file

@ -12,12 +12,6 @@
#include <wayland-server-core.h>
#include <wlr/types/wlr_seat.h>
/**
* Deprecated: this protocol is legacy and superseded by ext-data-control-v1.
* The implementation will be dropped in a future wlroots version.
*
* Consider using `wlr_ext_data_control_manager_v1` as a replacement.
*/
struct wlr_data_control_manager_v1 {
struct wl_global *global;
struct wl_list devices; // wlr_data_control_device_v1.link
@ -27,9 +21,7 @@ struct wlr_data_control_manager_v1 {
struct wl_signal new_device; // wlr_data_control_device_v1
} events;
struct {
struct wl_listener display_destroy;
} WLR_PRIVATE;
struct wl_listener display_destroy;
};
struct wlr_data_control_device_v1 {
@ -41,11 +33,9 @@ struct wlr_data_control_device_v1 {
struct wl_resource *selection_offer_resource; // current selection offer
struct wl_resource *primary_selection_offer_resource; // current primary selection offer
struct {
struct wl_listener seat_destroy;
struct wl_listener seat_set_selection;
struct wl_listener seat_set_primary_selection;
} WLR_PRIVATE;
struct wl_listener seat_destroy;
struct wl_listener seat_set_selection;
struct wl_listener seat_set_primary_selection;
};
struct wlr_data_control_manager_v1 *wlr_data_control_manager_v1_create(

View file

@ -16,15 +16,13 @@ struct wlr_data_device_manager {
struct wl_global *global;
struct wl_list data_sources;
struct wl_listener display_destroy;
struct {
struct wl_signal destroy;
} events;
void *data;
struct {
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
enum wlr_data_offer_type {
@ -42,9 +40,7 @@ struct wlr_data_offer {
enum wl_data_device_manager_dnd_action preferred_action;
bool in_ask;
struct {
struct wl_listener source_destroy;
} WLR_PRIVATE;
struct wl_listener source_destroy;
};
/**
@ -93,11 +89,9 @@ struct wlr_drag_icon {
struct wl_signal destroy;
} events;
void *data;
struct wl_listener surface_destroy;
struct {
struct wl_listener surface_destroy;
} WLR_PRIVATE;
void *data;
};
enum wlr_drag_grab_type {
@ -130,14 +124,11 @@ struct wlr_drag {
struct wl_signal destroy;
} events;
void *data;
struct wl_listener source_destroy;
struct wl_listener seat_client_destroy;
struct wl_listener icon_destroy;
struct {
struct wl_listener source_destroy;
struct wl_listener seat_client_destroy;
struct wl_listener focus_destroy;
struct wl_listener icon_destroy;
} WLR_PRIVATE;
void *data;
};
struct wlr_drag_motion_event {

View file

@ -21,9 +21,7 @@ struct wlr_drm_buffer {
struct wl_resource *resource; // can be NULL if the client destroyed it
struct wlr_dmabuf_attributes dmabuf;
struct {
struct wl_listener release;
} WLR_PRIVATE;
struct wl_listener release;
};
/**
@ -42,12 +40,12 @@ struct wlr_drm {
struct wl_signal destroy;
} events;
struct {
char *node_name;
struct wlr_drm_format_set formats;
// private state
struct wl_listener display_destroy;
} WLR_PRIVATE;
char *node_name;
struct wlr_drm_format_set formats;
struct wl_listener display_destroy;
};
struct wlr_drm_buffer *wlr_drm_buffer_try_from_resource(

View file

@ -18,10 +18,9 @@ struct wlr_drm_lease_v1_manager {
struct wl_list devices; // wlr_drm_lease_device_v1.link
struct wl_display *display;
struct wl_listener display_destroy;
struct {
struct wl_signal destroy;
/**
* Upon receiving this signal, call
* wlr_drm_lease_device_v1_grant_lease_request() to grant a lease of the
@ -30,10 +29,6 @@ struct wlr_drm_lease_v1_manager {
*/
struct wl_signal request;
} events;
struct {
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
struct wlr_drm_lease_device_v1 {
@ -48,11 +43,9 @@ struct wlr_drm_lease_device_v1 {
struct wl_list requests; // wlr_drm_lease_request_v1.link
struct wl_list link; // wlr_drm_lease_v1_manager.devices
void *data;
struct wl_listener backend_destroy;
struct {
struct wl_listener backend_destroy;
} WLR_PRIVATE;
void *data;
};
struct wlr_drm_lease_v1;
@ -62,12 +55,12 @@ struct wlr_drm_lease_connector_v1 {
struct wlr_output *output;
struct wlr_drm_lease_device_v1 *device;
/** NULL if no client is currently leasing this connector */
struct wlr_drm_lease_v1 *active_lease;
struct wl_listener destroy;
struct wl_list link; // wlr_drm_lease_device_v1.connectors
struct {
struct wl_listener destroy;
} WLR_PRIVATE;
};
struct wlr_drm_lease_request_v1 {
@ -91,13 +84,14 @@ struct wlr_drm_lease_v1 {
struct wlr_drm_lease_device_v1 *device;
struct wlr_drm_lease_connector_v1 **connectors;
size_t n_connectors;
struct wl_list link; // wlr_drm_lease_device_v1.leases
void *data;
struct wl_listener destroy;
struct {
struct wl_listener destroy;
} WLR_PRIVATE;
void *data;
};
/**

View file

@ -17,13 +17,11 @@ struct wlr_export_dmabuf_manager_v1 {
struct wl_global *global;
struct wl_list frames; // wlr_export_dmabuf_frame_v1.link
struct wl_listener display_destroy;
struct {
struct wl_signal destroy;
} events;
struct {
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
struct wlr_export_dmabuf_frame_v1 {
@ -35,10 +33,8 @@ struct wlr_export_dmabuf_frame_v1 {
bool cursor_locked;
struct {
struct wl_listener output_commit;
struct wl_listener output_destroy;
} WLR_PRIVATE;
struct wl_listener output_commit;
struct wl_listener output_destroy;
};
struct wlr_export_dmabuf_manager_v1 *wlr_export_dmabuf_manager_v1_create(

View file

@ -1,51 +0,0 @@
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif
#ifndef WLR_TYPES_WLR_EXT_DATA_CONTROL_V1_H
#define WLR_TYPES_WLR_EXT_DATA_CONTROL_V1_H
#include <wayland-server-core.h>
#include <wlr/types/wlr_seat.h>
struct wlr_ext_data_control_manager_v1 {
struct wl_global *global;
struct wl_list devices; // wlr_ext_data_control_device_v1.link
struct {
struct wl_signal destroy;
struct wl_signal new_device; // wlr_ext_data_control_device_v1
} events;
struct {
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
struct wlr_ext_data_control_device_v1 {
struct wl_resource *resource;
struct wlr_ext_data_control_manager_v1 *manager;
struct wl_list link; // wlr_ext_data_control_manager_v1.devices
struct wlr_seat *seat;
struct wl_resource *selection_offer_resource; // current selection offer
struct wl_resource *primary_selection_offer_resource; // current primary selection offer
struct {
struct wl_listener seat_destroy;
struct wl_listener seat_set_selection;
struct wl_listener seat_set_primary_selection;
} WLR_PRIVATE;
};
struct wlr_ext_data_control_manager_v1 *wlr_ext_data_control_manager_v1_create(
struct wl_display *display, uint32_t version);
void wlr_ext_data_control_device_v1_destroy(
struct wlr_ext_data_control_device_v1 *device);
#endif

View file

@ -16,15 +16,13 @@ struct wlr_ext_foreign_toplevel_list_v1 {
struct wl_list resources; // wl_resource_get_link()
struct wl_list toplevels; // ext_foreign_toplevel_handle_v1.link
struct wl_listener display_destroy;
struct {
struct wl_signal destroy;
} events;
void *data;
struct {
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
struct wlr_ext_foreign_toplevel_handle_v1 {
@ -66,7 +64,4 @@ void wlr_ext_foreign_toplevel_handle_v1_update_state(
struct wlr_ext_foreign_toplevel_handle_v1 *toplevel,
const struct wlr_ext_foreign_toplevel_handle_v1_state *state);
struct wlr_ext_foreign_toplevel_handle_v1 *wlr_ext_foreign_toplevel_handle_v1_from_resource(
struct wl_resource *resource);
#endif

View file

@ -1,134 +0,0 @@
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif
#ifndef WLR_TYPES_WLR_EXT_IMAGE_CAPTURE_SOURCE_V1_H
#define WLR_TYPES_WLR_EXT_IMAGE_CAPTURE_SOURCE_V1_H
#include <pixman.h>
#include <wayland-server-core.h>
#include <wlr/render/drm_format_set.h>
struct wlr_scene_node;
struct wlr_allocator;
struct wlr_renderer;
/**
* A screen capture source.
*
* When the size, device or formats change, the constraints_update event is
* emitted.
*
* The device and formats advertised are suitable for copying into a
* struct wlr_buffer.
*/
struct wlr_ext_image_capture_source_v1 {
const struct wlr_ext_image_capture_source_v1_interface *impl;
struct wl_list resources; // wl_resource_get_link()
uint32_t width, height;
uint32_t *shm_formats;
size_t shm_formats_len;
dev_t dmabuf_device;
struct wlr_drm_format_set dmabuf_formats;
struct {
struct wl_signal constraints_update;
struct wl_signal frame; // struct wlr_ext_image_capture_source_v1_frame_event
struct wl_signal destroy;
} events;
};
/**
* Event indicating that the source has produced a new frame.
*/
struct wlr_ext_image_capture_source_v1_frame_event {
const pixman_region32_t *damage;
};
/**
* A cursor capture source.
*
* Provides additional cursor-specific functionality on top of
* struct wlr_ext_image_capture_source_v1.
*/
struct wlr_ext_image_capture_source_v1_cursor {
struct wlr_ext_image_capture_source_v1 base;
bool entered;
int32_t x, y;
struct {
int32_t x, y;
} hotspot;
struct {
struct wl_signal update;
} events;
};
/**
* Interface exposing one screen capture source per output.
*/
struct wlr_ext_output_image_capture_source_manager_v1 {
struct wl_global *global;
struct {
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
/**
* Interface exposing one screen capture source per foreign toplevel.
*/
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 {
struct wl_global *global;
struct {
struct wl_signal destroy;
struct wl_signal new_request; // struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request
} events;
struct {
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request {
struct wlr_ext_foreign_toplevel_handle_v1 *toplevel_handle;
struct wl_client *client;
struct {
uint32_t new_id;
} WLR_PRIVATE;
};
/**
* Obtain a struct wlr_ext_image_capture_source_v1 from an ext_image_capture_source_v1
* resource.
*
* Asserts that the resource has the correct type. Returns NULL if the resource
* is inert.
*/
struct wlr_ext_image_capture_source_v1 *wlr_ext_image_capture_source_v1_from_resource(struct wl_resource *resource);
struct wlr_ext_output_image_capture_source_manager_v1 *wlr_ext_output_image_capture_source_manager_v1_create(
struct wl_display *display, uint32_t version);
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *
wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(struct wl_display *display, uint32_t version);
bool wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept(
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request *request,
struct wlr_ext_image_capture_source_v1 *source);
struct wlr_ext_image_capture_source_v1 *wlr_ext_image_capture_source_v1_create_with_scene_node(
struct wlr_scene_node *node, struct wl_event_loop *event_loop,
struct wlr_allocator *allocator, struct wlr_renderer *renderer);
#endif

Some files were not shown because too many files have changed in this diff Show more