Compare commits

..

No commits in common. "master" and "0.18.0" have entirely different histories.

323 changed files with 3699 additions and 13574 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

@ -20,18 +20,19 @@ packages:
- x11/xcb-util-errors
- x11/xcb-util-renderutil
- x11/xcb-util-wm
- x11-servers/xwayland
- x11-servers/xwayland-devel
- 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) {
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,10 +234,36 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
goto error_event;
}
if (drm->parent && !init_mgpu_renderer(drm)) {
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;
wl_signal_add(&session->events.destroy, &drm->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;
@ -398,7 +396,6 @@ void finish_drm_resources(struct wlr_drm_backend *drm) {
struct wlr_drm_plane *plane = &drm->planes[i];
drm_plane_finish_surface(plane);
wlr_drm_format_set_finish(&plane->formats);
free(plane->cursor_sizes);
}
free(drm->planes);
@ -556,7 +553,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 +576,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);
}
}
}
}
@ -621,7 +607,6 @@ static bool drm_commit(struct wlr_drm_backend *drm,
if (page_flip == NULL) {
return false;
}
page_flip->async = (flags & DRM_MODE_PAGE_FLIP_ASYNC);
}
bool ok = drm->iface->commit(drm, state, page_flip, flags, test_only);
@ -645,8 +630,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 +639,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 +666,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 +687,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 +701,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 +717,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 +734,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 +742,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,13 +784,14 @@ 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 &&
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) &&
state->adaptive_sync_enabled &&
@ -842,36 +801,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 +871,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 +1068,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 +1082,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 +1102,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 +1132,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 +1155,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 +1182,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 +1211,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 +1348,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 +1476,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 +1554,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 +1572,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 +1590,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 +1636,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");
}
free(edid);
char *subconnector = NULL;
@ -1787,10 +1702,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 +1779,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 +1820,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 +1970,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;
@ -1993,12 +2008,6 @@ static void handle_page_flip(int fd, unsigned seq,
if (conn != NULL) {
conn->pending_page_flip = NULL;
}
uint32_t present_flags = WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION;
if (!page_flip->async) {
present_flags |= WLR_OUTPUT_PRESENT_VSYNC;
}
if (page_flip->connectors_len == 0) {
drm_page_flip_destroy(page_flip);
}
@ -2029,23 +2038,26 @@ static void handle_page_flip(int fd, unsigned seq,
drm_fb_move(&layer->current_fb, &layer->queued_fb);
}
uint32_t present_flags = WLR_OUTPUT_PRESENT_VSYNC |
WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION;
/* Don't report ZERO_COPY in multi-gpu situations, because we had to copy
* 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 +2191,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 +2213,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 +2227,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,27 +39,7 @@ 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 (!modeset) {
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;
@ -77,7 +55,6 @@ static bool legacy_crtc_test(const struct wlr_drm_connector_state *state,
return false;
}
}
}
return true;
}
@ -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,17 +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_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);
}
@ -123,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;
@ -134,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;
@ -167,16 +152,27 @@ 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;
}
}
if (st->orig[i] == UNMATCHED) {
st->res[i] = UNMATCHED;
if (match_obj_(st, skips, score, replaced, i + 1)) {
has_best = true;
}
}
@ -184,29 +180,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;
}
@ -215,37 +211,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)) {
has_best = true;
if (has_best) {
return true;
}
return has_best;
// Maybe this resource can't be matched
st->res[i] = UNMATCHED;
return match_obj_(st, skips, score, replaced, i + 1);
}
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) {
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,11 +516,6 @@ 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);
@ -546,8 +523,7 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
if (pci) {
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
if (id && strcmp(id, "1") == 0) {
is_primary = true;
}
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);
@ -183,9 +178,7 @@ static void linux_dmabuf_feedback_v1_handle_main_device(void *data,
"falling back to primary node", name);
}
struct wlr_wl_backend *wl = feedback_data->backend;
assert(wl->drm_render_name == NULL);
wl->drm_render_name = strdup(name);
feedback_data->backend->drm_render_name = strdup(name);
drmFreeDevice(&device);
}
@ -312,7 +305,6 @@ static char *get_render_name(const char *name) {
static void legacy_drm_handle_device(void *data, struct wl_drm *drm,
const char *name) {
struct wlr_wl_backend *wl = data;
assert(wl->drm_render_name == NULL);
wl->drm_render_name = get_render_name(name);
}
@ -416,9 +408,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 +481,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 +515,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 +540,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 +551,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 +589,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 +601,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,10 +621,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;
struct wlr_wl_linux_dmabuf_feedback_v1 feedback_data = { .backend = wl };
if (wl->zwp_linux_dmabuf_v1 != NULL &&
@ -662,27 +638,18 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop,
if (wl->legacy_drm != NULL) {
wl_drm_destroy(wl->legacy_drm);
wl->legacy_drm = NULL;
free(wl->drm_render_name);
wl->drm_render_name = NULL;
}
}
wl_display_roundtrip(wl->remote_display); // get linux-dmabuf feedback events
wl_display_roundtrip(wl->remote_display); // get linux-dmabuf formats
if (feedback_data.format_table != NULL) {
munmap(feedback_data.format_table, feedback_data.format_table_size);
}
if (linux_dmabuf_feedback_v1 != NULL) {
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 +693,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;
}
}
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) {
if (wl_display_dispatch(output->backend->remote_display) == -1) {
wlr_log(WLR_ERROR, "wl_display_dispatch() failed");
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

@ -87,14 +87,16 @@ static void output_handle_frame(struct wl_listener *listener, void *data) {
layers_arr.size / sizeof(struct wlr_output_layer_state));
if (!wlr_output_test_state(output->wlr_output, &output_state)) {
wlr_log(WLR_ERROR, "wlr_output_test_state() failed");
wlr_log(WLR_ERROR, "wlr_output_test() failed");
return;
}
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;
};
/**
@ -178,8 +164,6 @@ struct wlr_drm_page_flip {
struct wl_list link; // wlr_drm_connector.page_flips
struct wlr_drm_page_flip_connector *connectors;
size_t connectors_len;
// True if DRM_MODE_PAGE_FLIP_ASYNC was set
bool async;
};
struct wlr_drm_page_flip_connector {
@ -214,10 +198,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 +211,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;
};
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 {
struct wl_signal ready;
} events;
// private state
int ev_fd;
struct wl_event_source *event_source;
wlr_drm_syncobj_timeline_ready_callback callback;
} WLR_PRIVATE;
};
/**
@ -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 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 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 {
// private state
const struct wlr_renderer_impl *impl;
} WLR_PRIVATE;
};
/**

View file

@ -20,9 +20,9 @@ struct wlr_alpha_modifier_surface_v1_state {
struct wlr_alpha_modifier_v1 {
struct wl_global *global;
struct {
// private state
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
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 {
// private state
struct wl_listener source_destroy;
struct wl_listener renderer_destroy;
size_t n_ignore_locks;
} WLR_PRIVATE;
};
/**
@ -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 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,7 +210,8 @@ struct wlr_surface {
struct wlr_addon_set addons;
void *data;
struct {
// private state
struct wl_listener role_resource_destroy;
struct {
@ -266,7 +237,6 @@ struct wlr_surface {
struct wl_resource *pending_buffer_resource;
struct wl_listener pending_buffer_resource_destroy;
} WLR_PRIVATE;
};
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 {
// private state
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
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 {
// private state
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
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 {
// private state
pixman_region32_t previous[WLR_DAMAGE_RING_PREVIOUS_LEN];
size_t previous_idx;
struct wl_list buffers; // wlr_damage_ring_buffer.link
} WLR_PRIVATE;
};
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 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 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;
};
/**
@ -93,11 +89,9 @@ struct wlr_drag_icon {
struct wl_signal destroy;
} events;
void *data;
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 {
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;
};
/**
@ -42,12 +40,12 @@ struct wlr_drm {
struct wl_signal destroy;
} events;
struct {
// private state
char *node_name;
struct wlr_drm_format_set formats;
struct wl_listener display_destroy;
} WLR_PRIVATE;
};
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 {
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 {
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 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