mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-11-03 09:01:40 -05:00 
			
		
		
		
	Compare commits
	
		
			No commits in common. "master" and "0.18.0" have entirely different histories.
		
	
	
		
	
		
					 323 changed files with 3699 additions and 13574 deletions
				
			
		| 
						 | 
				
			
			@ -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/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 ]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,2 +1 @@
 | 
			
		|||
/subprojects/*
 | 
			
		||||
!/subprojects/*.wrap
 | 
			
		||||
/subprojects/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								.mailmap
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								.mailmap
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,2 +1 @@
 | 
			
		|||
Isaac Freund <mail@isaacfreund.com> <ifreund@ifreund.xyz>
 | 
			
		||||
Kirill Primak <vyivel@eclair.cafe> <vyivel@posteo.net>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,16 +1,13 @@
 | 
			
		|||
#include <drm_fourcc.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <wlr/render/drm_syncobj.h>
 | 
			
		||||
#include <wlr/util/box.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
#include <xf86drm.h>
 | 
			
		||||
#include <xf86drmMode.h>
 | 
			
		||||
#include "backend/drm/drm.h"
 | 
			
		||||
#include "backend/drm/fb.h"
 | 
			
		||||
#include "backend/drm/iface.h"
 | 
			
		||||
#include "backend/drm/util.h"
 | 
			
		||||
#include "render/color.h"
 | 
			
		||||
 | 
			
		||||
static char *atomic_commit_flags_str(uint32_t flags) {
 | 
			
		||||
	const char *const l[] = {
 | 
			
		||||
| 
						 | 
				
			
			@ -155,20 +152,18 @@ static bool create_gamma_lut_blob(struct wlr_drm_backend *drm,
 | 
			
		|||
 | 
			
		||||
bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm,
 | 
			
		||||
		int width, int height, const pixman_region32_t *damage, uint32_t *blob_id) {
 | 
			
		||||
	if (!pixman_region32_not_empty(damage)) {
 | 
			
		||||
		*blob_id = 0;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pixman_region32_t clipped;
 | 
			
		||||
	pixman_region32_init(&clipped);
 | 
			
		||||
	pixman_region32_intersect_rect(&clipped, damage, 0, 0, width, height);
 | 
			
		||||
 | 
			
		||||
	int rects_len;
 | 
			
		||||
	const pixman_box32_t *rects = pixman_region32_rectangles(&clipped, &rects_len);
 | 
			
		||||
 | 
			
		||||
	int ret;
 | 
			
		||||
	if (rects_len > 0) {
 | 
			
		||||
		ret = drmModeCreatePropertyBlob(drm->fd, rects, sizeof(*rects) * rects_len, blob_id);
 | 
			
		||||
	} else {
 | 
			
		||||
		ret = 0;
 | 
			
		||||
		*blob_id = 0;
 | 
			
		||||
	}
 | 
			
		||||
	int ret = drmModeCreatePropertyBlob(drm->fd, rects, sizeof(*rects) * rects_len, blob_id);
 | 
			
		||||
	pixman_region32_fini(&clipped);
 | 
			
		||||
	if (ret != 0) {
 | 
			
		||||
		wlr_log_errno(WLR_ERROR, "Failed to create FB_DAMAGE_CLIPS property blob");
 | 
			
		||||
| 
						 | 
				
			
			@ -178,85 +173,6 @@ bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm,
 | 
			
		|||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t convert_cta861_eotf(enum wlr_color_transfer_function tf) {
 | 
			
		||||
	switch (tf) {
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
 | 
			
		||||
		abort(); // unsupported
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
 | 
			
		||||
		return 2;
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
 | 
			
		||||
		abort(); // unsupported
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
 | 
			
		||||
		abort(); // unsupported
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
 | 
			
		||||
		abort(); // unsupported
 | 
			
		||||
	}
 | 
			
		||||
	abort(); // unreachable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint16_t convert_cta861_color_coord(double v) {
 | 
			
		||||
	if (v < 0) {
 | 
			
		||||
		v = 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (v > 1) {
 | 
			
		||||
		v = 1;
 | 
			
		||||
	}
 | 
			
		||||
	return (uint16_t)round(v * 50000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool create_hdr_output_metadata_blob(struct wlr_drm_backend *drm,
 | 
			
		||||
		const struct wlr_output_image_description *img_desc, uint32_t *blob_id) {
 | 
			
		||||
	if (img_desc == NULL) {
 | 
			
		||||
		*blob_id = 0;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct hdr_output_metadata metadata = {
 | 
			
		||||
		.metadata_type = 0,
 | 
			
		||||
		.hdmi_metadata_type1 = {
 | 
			
		||||
			.eotf = convert_cta861_eotf(img_desc->transfer_function),
 | 
			
		||||
			.metadata_type = 0,
 | 
			
		||||
			.display_primaries = {
 | 
			
		||||
				{
 | 
			
		||||
					.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.red.x),
 | 
			
		||||
					.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.red.y),
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.green.x),
 | 
			
		||||
					.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.green.y),
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.blue.x),
 | 
			
		||||
					.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.blue.y),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			.white_point = {
 | 
			
		||||
				.x = convert_cta861_color_coord(img_desc->mastering_display_primaries.white.x),
 | 
			
		||||
				.y = convert_cta861_color_coord(img_desc->mastering_display_primaries.white.y),
 | 
			
		||||
			},
 | 
			
		||||
			.max_display_mastering_luminance = img_desc->mastering_luminance.max,
 | 
			
		||||
			.min_display_mastering_luminance = img_desc->mastering_luminance.min * 0.0001,
 | 
			
		||||
			.max_cll = img_desc->max_cll,
 | 
			
		||||
			.max_fall = img_desc->max_fall,
 | 
			
		||||
		},
 | 
			
		||||
	};
 | 
			
		||||
	if (drmModeCreatePropertyBlob(drm->fd, &metadata, sizeof(metadata), blob_id) != 0) {
 | 
			
		||||
		wlr_log_errno(WLR_ERROR, "Failed to create HDR_OUTPUT_METADATA property");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint64_t convert_primaries_to_colorspace(uint32_t primaries) {
 | 
			
		||||
	switch (primaries) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		return 0; // Default
 | 
			
		||||
	case WLR_COLOR_NAMED_PRIMARIES_BT2020:
 | 
			
		||||
		return 9; // BT2020_RGB
 | 
			
		||||
	}
 | 
			
		||||
	abort(); // unreachable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint64_t max_bpc_for_format(uint32_t format) {
 | 
			
		||||
	switch (format) {
 | 
			
		||||
	case DRM_FORMAT_XRGB2101010:
 | 
			
		||||
| 
						 | 
				
			
			@ -331,25 +247,19 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t gamma_lut = crtc->gamma_lut;
 | 
			
		||||
	if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
 | 
			
		||||
		size_t dim = 0;
 | 
			
		||||
		uint16_t *lut = NULL;
 | 
			
		||||
		if (state->base->color_transform != NULL) {
 | 
			
		||||
			struct wlr_color_transform_lut_3x1d *tr =
 | 
			
		||||
				color_transform_lut_3x1d_from_base(state->base->color_transform);
 | 
			
		||||
			dim = tr->dim;
 | 
			
		||||
			lut = tr->lut_3x1d;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	if (state->base->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
 | 
			
		||||
		// Fallback to legacy gamma interface when gamma properties are not
 | 
			
		||||
		// available (can happen on older Intel GPUs that support gamma but not
 | 
			
		||||
		// degamma).
 | 
			
		||||
		if (crtc->props.gamma_lut == 0) {
 | 
			
		||||
			if (!drm_legacy_crtc_set_gamma(drm, crtc, dim, lut)) {
 | 
			
		||||
			if (!drm_legacy_crtc_set_gamma(drm, crtc,
 | 
			
		||||
					state->base->gamma_lut_size,
 | 
			
		||||
					state->base->gamma_lut)) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if (!create_gamma_lut_blob(drm, dim, lut, &gamma_lut)) {
 | 
			
		||||
			if (!create_gamma_lut_blob(drm, state->base->gamma_lut_size,
 | 
			
		||||
					state->base->gamma_lut, &gamma_lut)) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -362,15 +272,6 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
 | 
			
		|||
			state->primary_fb->wlr_buf->height, &state->base->damage, &fb_damage_clips);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int in_fence_fd = -1;
 | 
			
		||||
	if (state->wait_timeline != NULL) {
 | 
			
		||||
		in_fence_fd = wlr_drm_syncobj_timeline_export_sync_file(state->wait_timeline,
 | 
			
		||||
			state->wait_point);
 | 
			
		||||
		if (in_fence_fd < 0) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool prev_vrr_enabled =
 | 
			
		||||
		output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
 | 
			
		||||
	bool vrr_enabled = prev_vrr_enabled;
 | 
			
		||||
| 
						 | 
				
			
			@ -381,25 +282,10 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
 | 
			
		|||
		vrr_enabled = state->base->adaptive_sync_enabled;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t colorspace = conn->colorspace;
 | 
			
		||||
	if (state->base->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
 | 
			
		||||
		colorspace = convert_primaries_to_colorspace(
 | 
			
		||||
			state->base->image_description ? state->base->image_description->primaries : 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t hdr_output_metadata = conn->hdr_output_metadata;
 | 
			
		||||
	if ((state->base->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) &&
 | 
			
		||||
			!create_hdr_output_metadata_blob(drm, state->base->image_description, &hdr_output_metadata)) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	state->mode_id = mode_id;
 | 
			
		||||
	state->gamma_lut = gamma_lut;
 | 
			
		||||
	state->fb_damage_clips = fb_damage_clips;
 | 
			
		||||
	state->primary_in_fence_fd = in_fence_fd;
 | 
			
		||||
	state->vrr_enabled = vrr_enabled;
 | 
			
		||||
	state->colorspace = colorspace;
 | 
			
		||||
	state->hdr_output_metadata = hdr_output_metadata;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -414,23 +300,11 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) {
 | 
			
		|||
	crtc->own_mode_id = true;
 | 
			
		||||
	commit_blob(drm, &crtc->mode_id, state->mode_id);
 | 
			
		||||
	commit_blob(drm, &crtc->gamma_lut, state->gamma_lut);
 | 
			
		||||
	commit_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
 | 
			
		||||
 | 
			
		||||
	conn->output.adaptive_sync_status = state->vrr_enabled ?
 | 
			
		||||
		WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED : WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED;
 | 
			
		||||
 | 
			
		||||
	destroy_blob(drm, state->fb_damage_clips);
 | 
			
		||||
	if (state->primary_in_fence_fd >= 0) {
 | 
			
		||||
		close(state->primary_in_fence_fd);
 | 
			
		||||
	}
 | 
			
		||||
	if (state->out_fence_fd >= 0) {
 | 
			
		||||
		// TODO: error handling
 | 
			
		||||
		wlr_drm_syncobj_timeline_import_sync_file(state->base->signal_timeline,
 | 
			
		||||
			state->base->signal_point, state->out_fence_fd);
 | 
			
		||||
		close(state->out_fence_fd);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn->colorspace = state->colorspace;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state) {
 | 
			
		||||
| 
						 | 
				
			
			@ -440,15 +314,8 @@ void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state)
 | 
			
		|||
 | 
			
		||||
	rollback_blob(drm, &crtc->mode_id, state->mode_id);
 | 
			
		||||
	rollback_blob(drm, &crtc->gamma_lut, state->gamma_lut);
 | 
			
		||||
	rollback_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
 | 
			
		||||
 | 
			
		||||
	destroy_blob(drm, state->fb_damage_clips);
 | 
			
		||||
	if (state->primary_in_fence_fd >= 0) {
 | 
			
		||||
		close(state->primary_in_fence_fd);
 | 
			
		||||
	}
 | 
			
		||||
	if (state->out_fence_fd >= 0) {
 | 
			
		||||
		close(state->out_fence_fd);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) {
 | 
			
		||||
| 
						 | 
				
			
			@ -460,8 +327,7 @@ static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) {
 | 
			
		|||
 | 
			
		||||
static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm,
 | 
			
		||||
		struct wlr_drm_plane *plane, struct wlr_drm_fb *fb, uint32_t crtc_id,
 | 
			
		||||
		const struct wlr_box *dst_box,
 | 
			
		||||
		const struct wlr_fbox *src_box) {
 | 
			
		||||
		int32_t x, int32_t y) {
 | 
			
		||||
	uint32_t id = plane->id;
 | 
			
		||||
	const struct wlr_drm_plane_props *props = &plane->props;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -471,50 +337,28 @@ static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm,
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t width = fb->wlr_buf->width;
 | 
			
		||||
	uint32_t height = fb->wlr_buf->height;
 | 
			
		||||
 | 
			
		||||
	// The src_* properties are in 16.16 fixed point
 | 
			
		||||
	atomic_add(atom, id, props->src_x, src_box->x * (1 << 16));
 | 
			
		||||
	atomic_add(atom, id, props->src_y, src_box->y * (1 << 16));
 | 
			
		||||
	atomic_add(atom, id, props->src_w, src_box->width * (1 << 16));
 | 
			
		||||
	atomic_add(atom, id, props->src_h, src_box->height * (1 << 16));
 | 
			
		||||
	atomic_add(atom, id, props->src_x, 0);
 | 
			
		||||
	atomic_add(atom, id, props->src_y, 0);
 | 
			
		||||
	atomic_add(atom, id, props->src_w, (uint64_t)width << 16);
 | 
			
		||||
	atomic_add(atom, id, props->src_h, (uint64_t)height << 16);
 | 
			
		||||
	atomic_add(atom, id, props->crtc_w, width);
 | 
			
		||||
	atomic_add(atom, id, props->crtc_h, height);
 | 
			
		||||
	atomic_add(atom, id, props->fb_id, fb->id);
 | 
			
		||||
	atomic_add(atom, id, props->crtc_id, crtc_id);
 | 
			
		||||
	atomic_add(atom, id, props->crtc_x, dst_box->x);
 | 
			
		||||
	atomic_add(atom, id, props->crtc_y, dst_box->y);
 | 
			
		||||
	atomic_add(atom, id, props->crtc_w, dst_box->width);
 | 
			
		||||
	atomic_add(atom, id, props->crtc_h, dst_box->height);
 | 
			
		||||
	atomic_add(atom, id, props->crtc_x, (uint64_t)x);
 | 
			
		||||
	atomic_add(atom, id, props->crtc_y, (uint64_t)y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool supports_cursor_hotspots(const struct wlr_drm_plane *plane) {
 | 
			
		||||
static bool supports_cursor_hotspots(const struct wlr_drm_plane* plane) {
 | 
			
		||||
	return plane->props.hotspot_x && plane->props.hotspot_y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_plane_in_fence_fd(struct atomic *atom,
 | 
			
		||||
		struct wlr_drm_plane *plane, int sync_file_fd) {
 | 
			
		||||
	if (!plane->props.in_fence_fd) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "Plane %"PRIu32 " is missing the IN_FENCE_FD property",
 | 
			
		||||
			plane->id);
 | 
			
		||||
		atom->failed = true;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	atomic_add(atom, plane->id, plane->props.in_fence_fd, sync_file_fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_crtc_out_fence_ptr(struct atomic *atom, struct wlr_drm_crtc *crtc,
 | 
			
		||||
		int *fd_ptr) {
 | 
			
		||||
	if (!crtc->props.out_fence_ptr) {
 | 
			
		||||
		wlr_log(WLR_ERROR,
 | 
			
		||||
			"CRTC %"PRIu32" is missing the OUT_FENCE_PTR property",
 | 
			
		||||
			crtc->id);
 | 
			
		||||
		atom->failed = true;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	atomic_add(atom, crtc->id, crtc->props.out_fence_ptr, (uintptr_t)fd_ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void atomic_connector_add(struct atomic *atom,
 | 
			
		||||
		struct wlr_drm_connector_state *state, bool modeset) {
 | 
			
		||||
		const struct wlr_drm_connector_state *state, bool modeset) {
 | 
			
		||||
	struct wlr_drm_connector *conn = state->connector;
 | 
			
		||||
	struct wlr_drm_backend *drm = conn->backend;
 | 
			
		||||
	struct wlr_drm_crtc *crtc = conn->crtc;
 | 
			
		||||
| 
						 | 
				
			
			@ -532,12 +376,6 @@ static void atomic_connector_add(struct atomic *atom,
 | 
			
		|||
	if (modeset && active && conn->props.max_bpc != 0 && conn->max_bpc_bounds[1] != 0) {
 | 
			
		||||
		atomic_add(atom, conn->id, conn->props.max_bpc, pick_max_bpc(conn, state->primary_fb));
 | 
			
		||||
	}
 | 
			
		||||
	if (conn->props.colorspace != 0) {
 | 
			
		||||
		atomic_add(atom, conn->id, conn->props.colorspace, state->colorspace);
 | 
			
		||||
	}
 | 
			
		||||
	if (conn->props.hdr_output_metadata != 0) {
 | 
			
		||||
		atomic_add(atom, conn->id, conn->props.hdr_output_metadata, state->hdr_output_metadata);
 | 
			
		||||
	}
 | 
			
		||||
	atomic_add(atom, crtc->id, crtc->props.mode_id, state->mode_id);
 | 
			
		||||
	atomic_add(atom, crtc->id, crtc->props.active, active);
 | 
			
		||||
	if (active) {
 | 
			
		||||
| 
						 | 
				
			
			@ -547,33 +385,16 @@ static void atomic_connector_add(struct atomic *atom,
 | 
			
		|||
		if (crtc->props.vrr_enabled != 0) {
 | 
			
		||||
			atomic_add(atom, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		set_plane_props(atom, drm, crtc->primary, state->primary_fb, crtc->id,
 | 
			
		||||
			&state->primary_viewport.dst_box, &state->primary_viewport.src_box);
 | 
			
		||||
			0, 0);
 | 
			
		||||
		if (crtc->primary->props.fb_damage_clips != 0) {
 | 
			
		||||
			atomic_add(atom, crtc->primary->id,
 | 
			
		||||
				crtc->primary->props.fb_damage_clips, state->fb_damage_clips);
 | 
			
		||||
		}
 | 
			
		||||
		if (state->primary_in_fence_fd >= 0) {
 | 
			
		||||
			set_plane_in_fence_fd(atom, crtc->primary, state->primary_in_fence_fd);
 | 
			
		||||
		}
 | 
			
		||||
		if (state->base->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
 | 
			
		||||
			set_crtc_out_fence_ptr(atom, crtc, &state->out_fence_fd);
 | 
			
		||||
		}
 | 
			
		||||
		if (crtc->cursor) {
 | 
			
		||||
			if (drm_connector_is_cursor_visible(conn)) {
 | 
			
		||||
				struct wlr_fbox cursor_src = {
 | 
			
		||||
					.width = state->cursor_fb->wlr_buf->width,
 | 
			
		||||
					.height = state->cursor_fb->wlr_buf->height,
 | 
			
		||||
				};
 | 
			
		||||
				struct wlr_box cursor_dst = {
 | 
			
		||||
					.x = conn->cursor_x,
 | 
			
		||||
					.y = conn->cursor_y,
 | 
			
		||||
					.width = state->cursor_fb->wlr_buf->width,
 | 
			
		||||
					.height = state->cursor_fb->wlr_buf->height,
 | 
			
		||||
				};
 | 
			
		||||
				set_plane_props(atom, drm, crtc->cursor, state->cursor_fb,
 | 
			
		||||
					crtc->id, &cursor_dst, &cursor_src);
 | 
			
		||||
					crtc->id, conn->cursor_x, conn->cursor_y);
 | 
			
		||||
				if (supports_cursor_hotspots(crtc->cursor)) {
 | 
			
		||||
					atomic_add(atom, crtc->cursor->id,
 | 
			
		||||
						crtc->cursor->props.hotspot_x, conn->cursor_hotspot_x);
 | 
			
		||||
| 
						 | 
				
			
			@ -616,7 +437,7 @@ static bool atomic_device_commit(struct wlr_drm_backend *drm,
 | 
			
		|||
	if (state->modeset) {
 | 
			
		||||
		flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
 | 
			
		||||
	}
 | 
			
		||||
	if (state->nonblock) {
 | 
			
		||||
	if (!test_only && state->nonblock) {
 | 
			
		||||
		flags |= DRM_MODE_ATOMIC_NONBLOCK;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -635,6 +456,33 @@ out:
 | 
			
		|||
	return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool drm_atomic_reset(struct wlr_drm_backend *drm) {
 | 
			
		||||
	struct atomic atom;
 | 
			
		||||
	atomic_begin(&atom);
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < drm->num_crtcs; i++) {
 | 
			
		||||
		struct wlr_drm_crtc *crtc = &drm->crtcs[i];
 | 
			
		||||
		atomic_add(&atom, crtc->id, crtc->props.mode_id, 0);
 | 
			
		||||
		atomic_add(&atom, crtc->id, crtc->props.active, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_drm_connector *conn;
 | 
			
		||||
	wl_list_for_each(conn, &drm->connectors, link) {
 | 
			
		||||
		atomic_add(&atom, conn->id, conn->props.crtc_id, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < drm->num_planes; i++) {
 | 
			
		||||
		plane_disable(&atom, &drm->planes[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
 | 
			
		||||
	bool ok = atomic_commit(&atom, drm, NULL, NULL, flags);
 | 
			
		||||
	atomic_finish(&atom);
 | 
			
		||||
 | 
			
		||||
	return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct wlr_drm_interface atomic_iface = {
 | 
			
		||||
	.commit = atomic_device_commit,
 | 
			
		||||
	.reset = drm_atomic_reset,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,10 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <drm_fourcc.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <wayland-server-core.h>
 | 
			
		||||
#include <wlr/backend/interface.h>
 | 
			
		||||
#include <wlr/backend/session.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +13,6 @@
 | 
			
		|||
#include <xf86drm.h>
 | 
			
		||||
#include "backend/drm/drm.h"
 | 
			
		||||
#include "backend/drm/fb.h"
 | 
			
		||||
#include "render/drm_format_set.h"
 | 
			
		||||
 | 
			
		||||
struct wlr_drm_backend *get_drm_backend_from_backend(
 | 
			
		||||
		struct wlr_backend *wlr_backend) {
 | 
			
		||||
| 
						 | 
				
			
			@ -52,8 +53,7 @@ static void backend_destroy(struct wlr_backend *backend) {
 | 
			
		|||
	wl_list_remove(&drm->dev_change.link);
 | 
			
		||||
	wl_list_remove(&drm->dev_remove.link);
 | 
			
		||||
 | 
			
		||||
	if (drm->mgpu_renderer.wlr_rend) {
 | 
			
		||||
		wlr_drm_format_set_finish(&drm->mgpu_formats);
 | 
			
		||||
	if (drm->parent) {
 | 
			
		||||
		finish_drm_renderer(&drm->mgpu_renderer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -75,6 +75,10 @@ static int backend_get_drm_fd(struct wlr_backend *backend) {
 | 
			
		|||
	return drm->fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t backend_get_buffer_caps(struct wlr_backend *backend) {
 | 
			
		||||
	return WLR_BUFFER_CAP_DMABUF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool backend_test(struct wlr_backend *backend,
 | 
			
		||||
		const struct wlr_backend_output_state *states, size_t states_len) {
 | 
			
		||||
	struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend);
 | 
			
		||||
| 
						 | 
				
			
			@ -91,6 +95,7 @@ static const struct wlr_backend_impl backend_impl = {
 | 
			
		|||
	.start = backend_start,
 | 
			
		||||
	.destroy = backend_destroy,
 | 
			
		||||
	.get_drm_fd = backend_get_drm_fd,
 | 
			
		||||
	.get_buffer_caps = backend_get_buffer_caps,
 | 
			
		||||
	.test = backend_test,
 | 
			
		||||
	.commit = backend_commit,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -112,18 +117,11 @@ static void handle_session_active(struct wl_listener *listener, void *data) {
 | 
			
		|||
	wlr_log(WLR_INFO, "DRM FD %s", session->active ? "resumed" : "paused");
 | 
			
		||||
 | 
			
		||||
	if (!session->active) {
 | 
			
		||||
		// Disconnect any active connectors so that the client will modeset and
 | 
			
		||||
		// rerender when the session is activated again.
 | 
			
		||||
		struct wlr_drm_connector *conn;
 | 
			
		||||
		wl_list_for_each(conn, &drm->connectors, link) {
 | 
			
		||||
			if (conn->status == DRM_MODE_CONNECTED) {
 | 
			
		||||
				wlr_output_destroy(&conn->output);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scan_drm_connectors(drm, NULL);
 | 
			
		||||
	restore_drm_device(drm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_dev_change(struct wl_listener *listener, void *data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -167,44 +165,6 @@ static void handle_parent_destroy(struct wl_listener *listener, void *data) {
 | 
			
		|||
	backend_destroy(&drm->backend);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sanitize_mgpu_modifiers(struct wlr_drm_format_set *set) {
 | 
			
		||||
	for (size_t idx = 0; idx < set->len; idx++) {
 | 
			
		||||
		// Implicit modifiers are not well-defined across devices, so strip
 | 
			
		||||
		// them from all formats in multi-gpu scenarios.
 | 
			
		||||
		struct wlr_drm_format *fmt = &set->formats[idx];
 | 
			
		||||
		wlr_drm_format_set_remove(set, fmt->format, DRM_FORMAT_MOD_INVALID);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool init_mgpu_renderer(struct wlr_drm_backend *drm) {
 | 
			
		||||
	if (!init_drm_renderer(drm, &drm->mgpu_renderer)) {
 | 
			
		||||
		wlr_log(WLR_INFO, "Failed to initialize mgpu blit renderer"
 | 
			
		||||
			", falling back to scanning out from primary GPU");
 | 
			
		||||
 | 
			
		||||
		for (uint32_t plane_idx = 0; plane_idx < drm->num_planes; plane_idx++) {
 | 
			
		||||
			struct wlr_drm_plane *plane = &drm->planes[plane_idx];
 | 
			
		||||
			sanitize_mgpu_modifiers(&plane->formats);
 | 
			
		||||
		}
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// We'll perform a multi-GPU copy for all submitted buffers, we need
 | 
			
		||||
	// to be able to texture from them
 | 
			
		||||
	struct wlr_renderer *renderer = drm->mgpu_renderer.wlr_rend;
 | 
			
		||||
	const struct wlr_drm_format_set *texture_formats =
 | 
			
		||||
		wlr_renderer_get_texture_formats(renderer, WLR_BUFFER_CAP_DMABUF);
 | 
			
		||||
	if (texture_formats == NULL) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "Failed to query renderer texture formats");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_drm_format_set_copy(&drm->mgpu_formats, texture_formats);
 | 
			
		||||
	sanitize_mgpu_modifiers(&drm->mgpu_formats);
 | 
			
		||||
	drm->backend.features.timeline = drm->backend.features.timeline &&
 | 
			
		||||
		drm->mgpu_renderer.wlr_rend->features.timeline;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
 | 
			
		||||
		struct wlr_device *dev, struct wlr_backend *parent) {
 | 
			
		||||
	assert(session && dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -232,8 +192,6 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
 | 
			
		|||
	}
 | 
			
		||||
	wlr_backend_init(&drm->backend, &backend_impl);
 | 
			
		||||
 | 
			
		||||
	drm->backend.buffer_caps = WLR_BUFFER_CAP_DMABUF;
 | 
			
		||||
 | 
			
		||||
	drm->session = session;
 | 
			
		||||
	wl_list_init(&drm->fbs);
 | 
			
		||||
	wl_list_init(&drm->connectors);
 | 
			
		||||
| 
						 | 
				
			
			@ -276,8 +234,34 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
 | 
			
		|||
		goto error_event;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (drm->parent && !init_mgpu_renderer(drm)) {
 | 
			
		||||
		goto error_mgpu_renderer;
 | 
			
		||||
	if (drm->parent) {
 | 
			
		||||
		if (!init_drm_renderer(drm, &drm->mgpu_renderer)) {
 | 
			
		||||
			wlr_log(WLR_ERROR, "Failed to initialize renderer");
 | 
			
		||||
			goto error_resources;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// We'll perform a multi-GPU copy for all submitted buffers, we need
 | 
			
		||||
		// to be able to texture from them
 | 
			
		||||
		struct wlr_renderer *renderer = drm->mgpu_renderer.wlr_rend;
 | 
			
		||||
		const struct wlr_drm_format_set *texture_formats =
 | 
			
		||||
			wlr_renderer_get_texture_formats(renderer, WLR_BUFFER_CAP_DMABUF);
 | 
			
		||||
		if (texture_formats == NULL) {
 | 
			
		||||
			wlr_log(WLR_ERROR, "Failed to query renderer texture formats");
 | 
			
		||||
			goto error_mgpu_renderer;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Forbid implicit modifiers, because their meaning changes from one
 | 
			
		||||
		// GPU to another.
 | 
			
		||||
		for (size_t i = 0; i < texture_formats->len; i++) {
 | 
			
		||||
			const struct wlr_drm_format *fmt = &texture_formats->formats[i];
 | 
			
		||||
			for (size_t j = 0; j < fmt->len; j++) {
 | 
			
		||||
				uint64_t mod = fmt->modifiers[j];
 | 
			
		||||
				if (mod == DRM_FORMAT_MOD_INVALID) {
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format, mod);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	drm->session_destroy.notify = handle_session_destroy;
 | 
			
		||||
| 
						 | 
				
			
			@ -287,6 +271,7 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session,
 | 
			
		|||
 | 
			
		||||
error_mgpu_renderer:
 | 
			
		||||
	finish_drm_renderer(&drm->mgpu_renderer);
 | 
			
		||||
error_resources:
 | 
			
		||||
	finish_drm_resources(drm);
 | 
			
		||||
error_event:
 | 
			
		||||
	wl_list_remove(&drm->session_active.link);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,12 +784,13 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo
 | 
			
		|||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled &&
 | 
			
		||||
			output->width == 0 && output->height == 0 &&
 | 
			
		||||
			!(state->committed & WLR_OUTPUT_STATE_MODE)) {
 | 
			
		||||
		wlr_drm_conn_log(conn, WLR_DEBUG,
 | 
			
		||||
			"Can't enable an output without a mode");
 | 
			
		||||
		return false;
 | 
			
		||||
	if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled) {
 | 
			
		||||
		if (output->current_mode == NULL &&
 | 
			
		||||
				!(state->committed & WLR_OUTPUT_STATE_MODE)) {
 | 
			
		||||
			wlr_drm_conn_log(conn, WLR_DEBUG,
 | 
			
		||||
				"Can't enable an output without a mode");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) &&
 | 
			
		||||
| 
						 | 
				
			
			@ -842,36 +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");
 | 
			
		||||
	}
 | 
			
		||||
	parse_edid(wlr_conn, edid_len, 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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,8 +7,6 @@
 | 
			
		|||
#include "backend/drm/fb.h"
 | 
			
		||||
#include "backend/drm/iface.h"
 | 
			
		||||
#include "backend/drm/util.h"
 | 
			
		||||
#include "render/color.h"
 | 
			
		||||
#include "types/wlr_output.h"
 | 
			
		||||
 | 
			
		||||
static bool legacy_fb_props_match(struct wlr_drm_fb *fb1,
 | 
			
		||||
		struct wlr_drm_fb *fb2) {
 | 
			
		||||
| 
						 | 
				
			
			@ -41,41 +39,20 @@ static bool legacy_crtc_test(const struct wlr_drm_connector_state *state,
 | 
			
		|||
	struct wlr_drm_connector *conn = state->connector;
 | 
			
		||||
	struct wlr_drm_crtc *crtc = conn->crtc;
 | 
			
		||||
 | 
			
		||||
	if (state->base->committed & WLR_OUTPUT_STATE_BUFFER) {
 | 
			
		||||
		// If the size doesn't match, reject buffer (scaling is not supported)
 | 
			
		||||
		int pending_width, pending_height;
 | 
			
		||||
		output_pending_resolution(&state->connector->output, state->base,
 | 
			
		||||
			&pending_width, &pending_height);
 | 
			
		||||
		if (state->base->buffer->width != pending_width ||
 | 
			
		||||
				state->base->buffer->height != pending_height) {
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Primary buffer size mismatch");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		// Source crop is also not supported
 | 
			
		||||
		struct wlr_fbox src_box;
 | 
			
		||||
		output_state_get_buffer_src_box(state->base, &src_box);
 | 
			
		||||
		if (src_box.x != 0.0 || src_box.y != 0.0 ||
 | 
			
		||||
				src_box.width != (double)state->base->buffer->width ||
 | 
			
		||||
				src_box.height != (double)state->base->buffer->height) {
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Source crop not supported in DRM-legacy output");
 | 
			
		||||
			return false;
 | 
			
		||||
	if ((state->base->committed & WLR_OUTPUT_STATE_BUFFER) && !modeset) {
 | 
			
		||||
		struct wlr_drm_fb *pending_fb = state->primary_fb;
 | 
			
		||||
 | 
			
		||||
		struct wlr_drm_fb *prev_fb = crtc->primary->queued_fb;
 | 
			
		||||
		if (!prev_fb) {
 | 
			
		||||
			prev_fb = crtc->primary->current_fb;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!modeset) {
 | 
			
		||||
			struct wlr_drm_fb *pending_fb = state->primary_fb;
 | 
			
		||||
 | 
			
		||||
			struct wlr_drm_fb *prev_fb = crtc->primary->queued_fb;
 | 
			
		||||
			if (!prev_fb) {
 | 
			
		||||
				prev_fb = crtc->primary->current_fb;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* Legacy is only guaranteed to be able to display a FB if it's been
 | 
			
		||||
			* allocated the same way as the previous one. */
 | 
			
		||||
			if (prev_fb != NULL && !legacy_fb_props_match(prev_fb, pending_fb)) {
 | 
			
		||||
				wlr_drm_conn_log(conn, WLR_DEBUG,
 | 
			
		||||
					"Cannot change scan-out buffer parameters with legacy KMS API");
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		/* Legacy is only guaranteed to be able to display a FB if it's been
 | 
			
		||||
		 * allocated the same way as the previous one. */
 | 
			
		||||
		if (prev_fb != NULL && !legacy_fb_props_match(prev_fb, pending_fb)) {
 | 
			
		||||
			wlr_drm_conn_log(conn, WLR_DEBUG,
 | 
			
		||||
				"Cannot change scan-out buffer parameters with legacy KMS API");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -125,17 +102,9 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
 | 
			
		||||
		size_t dim = 0;
 | 
			
		||||
		uint16_t *lut = NULL;
 | 
			
		||||
		if (state->base->color_transform != NULL) {
 | 
			
		||||
			struct wlr_color_transform_lut_3x1d *tr =
 | 
			
		||||
				color_transform_lut_3x1d_from_base(state->base->color_transform);
 | 
			
		||||
			dim = tr->dim;
 | 
			
		||||
			lut = tr->lut_3x1d;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!drm_legacy_crtc_set_gamma(drm, crtc, dim, lut)) {
 | 
			
		||||
	if (state->base->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
 | 
			
		||||
		if (!drm_legacy_crtc_set_gamma(drm, crtc,
 | 
			
		||||
				state->base->gamma_lut_size, state->base->gamma_lut)) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -159,7 +128,7 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
 | 
			
		|||
			state->base->adaptive_sync_enabled ? "enabled" : "disabled");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cursor != NULL && state->active && drm_connector_is_cursor_visible(conn)) {
 | 
			
		||||
	if (cursor != NULL && drm_connector_is_cursor_visible(conn)) {
 | 
			
		||||
		struct wlr_drm_fb *cursor_fb = state->cursor_fb;
 | 
			
		||||
		if (cursor_fb == NULL) {
 | 
			
		||||
			wlr_drm_conn_log(conn, WLR_DEBUG, "Failed to acquire cursor FB");
 | 
			
		||||
| 
						 | 
				
			
			@ -201,9 +170,7 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Legacy uAPI doesn't support requesting page-flip events when
 | 
			
		||||
	// turning off a CRTC
 | 
			
		||||
	if (state->active && (flags & DRM_MODE_PAGE_FLIP_EVENT)) {
 | 
			
		||||
	if (flags & DRM_MODE_PAGE_FLIP_EVENT) {
 | 
			
		||||
		if (drmModePageFlip(drm->fd, crtc->id, fb_id, flags, page_flip)) {
 | 
			
		||||
			wlr_drm_conn_log_errno(conn, WLR_ERROR, "drmModePageFlip failed");
 | 
			
		||||
			return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -281,6 +248,20 @@ bool drm_legacy_crtc_set_gamma(struct wlr_drm_backend *drm,
 | 
			
		|||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool legacy_reset(struct wlr_drm_backend *drm) {
 | 
			
		||||
	bool ok = true;
 | 
			
		||||
	for (size_t i = 0; i < drm->num_crtcs; i++) {
 | 
			
		||||
		struct wlr_drm_crtc *crtc = &drm->crtcs[i];
 | 
			
		||||
		if (drmModeSetCrtc(drm->fd, crtc->id, 0, 0, 0, NULL, 0, NULL) != 0) {
 | 
			
		||||
			wlr_log_errno(WLR_ERROR, "Failed to disable CRTC %"PRIu32,
 | 
			
		||||
				crtc->id);
 | 
			
		||||
			ok = false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct wlr_drm_interface legacy_iface = {
 | 
			
		||||
	.commit = legacy_commit,
 | 
			
		||||
	.reset = legacy_reset,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -191,40 +191,32 @@ static int handle_udev_event(int fd, uint32_t mask, void *data) {
 | 
			
		|||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_t devnum = udev_device_get_devnum(udev_dev);
 | 
			
		||||
	if (strcmp(action, "add") == 0) {
 | 
			
		||||
		struct wlr_device *dev;
 | 
			
		||||
		wl_list_for_each(dev, &session->devices, link) {
 | 
			
		||||
			if (dev->dev == devnum) {
 | 
			
		||||
				wlr_log(WLR_DEBUG, "Skipping duplicate device %s", sysname);
 | 
			
		||||
				goto out;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		wlr_log(WLR_DEBUG, "DRM device %s added", sysname);
 | 
			
		||||
		struct wlr_session_add_event event = {
 | 
			
		||||
			.path = devnode,
 | 
			
		||||
		};
 | 
			
		||||
		wl_signal_emit_mutable(&session->events.add_drm_card, &event);
 | 
			
		||||
	} else if (strcmp(action, "change") == 0) {
 | 
			
		||||
	} else if (strcmp(action, "change") == 0 || strcmp(action, "remove") == 0) {
 | 
			
		||||
		dev_t devnum = udev_device_get_devnum(udev_dev);
 | 
			
		||||
		struct wlr_device *dev;
 | 
			
		||||
		wl_list_for_each(dev, &session->devices, link) {
 | 
			
		||||
			if (dev->dev == devnum) {
 | 
			
		||||
			if (dev->dev != devnum) {
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (strcmp(action, "change") == 0) {
 | 
			
		||||
				wlr_log(WLR_DEBUG, "DRM device %s changed", sysname);
 | 
			
		||||
				struct wlr_device_change_event event = {0};
 | 
			
		||||
				read_udev_change_event(&event, udev_dev);
 | 
			
		||||
				wl_signal_emit_mutable(&dev->events.change, &event);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else if (strcmp(action, "remove") == 0) {
 | 
			
		||||
		struct wlr_device *dev;
 | 
			
		||||
		wl_list_for_each(dev, &session->devices, link) {
 | 
			
		||||
			if (dev->dev == devnum) {
 | 
			
		||||
			} else if (strcmp(action, "remove") == 0) {
 | 
			
		||||
				wlr_log(WLR_DEBUG, "DRM device %s removed", sysname);
 | 
			
		||||
				wl_signal_emit_mutable(&dev->events.remove, NULL);
 | 
			
		||||
				break;
 | 
			
		||||
			} else {
 | 
			
		||||
				assert(0);
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -303,11 +295,6 @@ void wlr_session_destroy(struct wlr_session *session) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	wl_signal_emit_mutable(&session->events.destroy, session);
 | 
			
		||||
 | 
			
		||||
	assert(wl_list_empty(&session->events.active.listener_list));
 | 
			
		||||
	assert(wl_list_empty(&session->events.add_drm_card.listener_list));
 | 
			
		||||
	assert(wl_list_empty(&session->events.destroy.listener_list));
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&session->event_loop_destroy.link);
 | 
			
		||||
 | 
			
		||||
	wl_event_source_remove(session->udev_event);
 | 
			
		||||
| 
						 | 
				
			
			@ -365,13 +352,6 @@ void wlr_session_close_file(struct wlr_session *session,
 | 
			
		|||
	if (libseat_close_device(session->seat_handle, dev->device_id) == -1) {
 | 
			
		||||
		wlr_log_errno(WLR_ERROR, "Failed to close device %d", dev->device_id);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert(wl_list_empty(&dev->events.change.listener_list));
 | 
			
		||||
	// TODO: assert that the "remove" listener list is empty as well. Listeners
 | 
			
		||||
	// will typically call wlr_session_close_file() in response, and
 | 
			
		||||
	// wl_signal_emit_mutable() installs two phantom listeners, so we'd count
 | 
			
		||||
	// these two.
 | 
			
		||||
 | 
			
		||||
	close(dev->fd);
 | 
			
		||||
	wl_list_remove(&dev->link);
 | 
			
		||||
	free(dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -519,6 +499,8 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
 | 
			
		|||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bool is_boot_vga = false;
 | 
			
		||||
 | 
			
		||||
		const char *path = udev_list_entry_get_name(entry);
 | 
			
		||||
		struct udev_device *dev = udev_device_new_from_syspath(session->udev, path);
 | 
			
		||||
		if (!dev) {
 | 
			
		||||
| 
						 | 
				
			
			@ -534,20 +516,14 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
 | 
			
		|||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bool is_primary = false;
 | 
			
		||||
		const char *boot_display = udev_device_get_sysattr_value(dev, "boot_display");
 | 
			
		||||
		if (boot_display && strcmp(boot_display, "1") == 0) {
 | 
			
		||||
		    is_primary = true;
 | 
			
		||||
		} else {
 | 
			
		||||
			// This is owned by 'dev', so we don't need to free it
 | 
			
		||||
			struct udev_device *pci =
 | 
			
		||||
				udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
 | 
			
		||||
		// This is owned by 'dev', so we don't need to free it
 | 
			
		||||
		struct udev_device *pci =
 | 
			
		||||
			udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
 | 
			
		||||
 | 
			
		||||
			if (pci) {
 | 
			
		||||
				const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
 | 
			
		||||
				if (id && strcmp(id, "1") == 0) {
 | 
			
		||||
					is_primary = true;
 | 
			
		||||
				}
 | 
			
		||||
		if (pci) {
 | 
			
		||||
			const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
 | 
			
		||||
			if (id && strcmp(id, "1") == 0) {
 | 
			
		||||
				is_boot_vga = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -561,7 +537,7 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
 | 
			
		|||
		udev_device_unref(dev);
 | 
			
		||||
 | 
			
		||||
		ret[i] = wlr_dev;
 | 
			
		||||
		if (is_primary) {
 | 
			
		||||
		if (is_boot_vga) {
 | 
			
		||||
			struct wlr_device *tmp = ret[0];
 | 
			
		||||
			ret[0] = ret[i];
 | 
			
		||||
			ret[i] = tmp;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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, ®istry_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
 | 
			
		||||
 | 
			
		||||
		if (feedback_data.format_table != NULL) {
 | 
			
		||||
			munmap(feedback_data.format_table, feedback_data.format_table_size);
 | 
			
		||||
		}
 | 
			
		||||
	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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,6 @@
 | 
			
		|||
#include <wayland-client-protocol.h>
 | 
			
		||||
 | 
			
		||||
#include <wlr/interfaces/wlr_output.h>
 | 
			
		||||
#include <wlr/render/drm_syncobj.h>
 | 
			
		||||
#include <wlr/render/wlr_renderer.h>
 | 
			
		||||
#include <wlr/types/wlr_output_layer.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +20,6 @@
 | 
			
		|||
#include "types/wlr_output.h"
 | 
			
		||||
 | 
			
		||||
#include "linux-dmabuf-v1-client-protocol.h"
 | 
			
		||||
#include "linux-drm-syncobj-v1-client-protocol.h"
 | 
			
		||||
#include "presentation-time-client-protocol.h"
 | 
			
		||||
#include "viewporter-client-protocol.h"
 | 
			
		||||
#include "xdg-activation-v1-client-protocol.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -33,9 +31,7 @@ static const uint32_t SUPPORTED_OUTPUT_STATE =
 | 
			
		|||
	WLR_OUTPUT_STATE_BUFFER |
 | 
			
		||||
	WLR_OUTPUT_STATE_ENABLED |
 | 
			
		||||
	WLR_OUTPUT_STATE_MODE |
 | 
			
		||||
	WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED |
 | 
			
		||||
	WLR_OUTPUT_STATE_WAIT_TIMELINE |
 | 
			
		||||
	WLR_OUTPUT_STATE_SIGNAL_TIMELINE;
 | 
			
		||||
	WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED;
 | 
			
		||||
 | 
			
		||||
static size_t last_output_num = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -98,13 +94,14 @@ static void presentation_feedback_handle_presented(void *data,
 | 
			
		|||
		uint32_t seq_hi, uint32_t seq_lo, uint32_t flags) {
 | 
			
		||||
	struct wlr_wl_presentation_feedback *feedback = data;
 | 
			
		||||
 | 
			
		||||
	struct timespec t = {
 | 
			
		||||
		.tv_sec = ((uint64_t)tv_sec_hi << 32) | tv_sec_lo,
 | 
			
		||||
		.tv_nsec = tv_nsec,
 | 
			
		||||
	};
 | 
			
		||||
	struct wlr_output_event_present event = {
 | 
			
		||||
		.commit_seq = feedback->commit_seq,
 | 
			
		||||
		.presented = true,
 | 
			
		||||
		.when = {
 | 
			
		||||
			.tv_sec = ((uint64_t)tv_sec_hi << 32) | tv_sec_lo,
 | 
			
		||||
			.tv_nsec = tv_nsec,
 | 
			
		||||
		},
 | 
			
		||||
		.when = &t,
 | 
			
		||||
		.seq = ((uint64_t)seq_hi << 32) | seq_lo,
 | 
			
		||||
		.refresh = refresh_ns,
 | 
			
		||||
		.flags = flags,
 | 
			
		||||
| 
						 | 
				
			
			@ -134,11 +131,6 @@ static const struct wp_presentation_feedback_listener
 | 
			
		|||
	.discarded = presentation_feedback_handle_discarded,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void buffer_remove_drm_syncobj_waiter(struct wlr_wl_buffer *buffer) {
 | 
			
		||||
	wlr_drm_syncobj_timeline_waiter_finish(&buffer->drm_syncobj_waiter);
 | 
			
		||||
	buffer->has_drm_syncobj_waiter = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
 | 
			
		||||
	if (buffer == NULL) {
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -146,42 +138,22 @@ void destroy_wl_buffer(struct wlr_wl_buffer *buffer) {
 | 
			
		|||
	wl_list_remove(&buffer->buffer_destroy.link);
 | 
			
		||||
	wl_list_remove(&buffer->link);
 | 
			
		||||
	wl_buffer_destroy(buffer->wl_buffer);
 | 
			
		||||
	if (buffer->has_drm_syncobj_waiter) {
 | 
			
		||||
		buffer_remove_drm_syncobj_waiter(buffer);
 | 
			
		||||
	}
 | 
			
		||||
	if (!buffer->released) {
 | 
			
		||||
		wlr_buffer_unlock(buffer->buffer);
 | 
			
		||||
	}
 | 
			
		||||
	wlr_drm_syncobj_timeline_unref(buffer->fallback_signal_timeline);
 | 
			
		||||
	free(buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void buffer_release(struct wlr_wl_buffer *buffer) {
 | 
			
		||||
	if (buffer->released) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	buffer->released = true;
 | 
			
		||||
	wlr_buffer_unlock(buffer->buffer); // might free buffer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void buffer_handle_release(void *data, struct wl_buffer *wl_buffer) {
 | 
			
		||||
	struct wlr_wl_buffer *buffer = data;
 | 
			
		||||
	if (buffer->has_drm_syncobj_waiter) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	buffer_release(buffer);
 | 
			
		||||
	buffer->released = true;
 | 
			
		||||
	wlr_buffer_unlock(buffer->buffer); // might free buffer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wl_buffer_listener buffer_listener = {
 | 
			
		||||
	.release = buffer_handle_release,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void buffer_handle_drm_syncobj_ready(struct wlr_drm_syncobj_timeline_waiter *waiter) {
 | 
			
		||||
	struct wlr_wl_buffer *buffer = wl_container_of(waiter, buffer, drm_syncobj_waiter);
 | 
			
		||||
	buffer_remove_drm_syncobj_waiter(buffer);
 | 
			
		||||
	buffer_release(buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void buffer_handle_buffer_destroy(struct wl_listener *listener,
 | 
			
		||||
		void *data) {
 | 
			
		||||
	struct wlr_wl_buffer *buffer =
 | 
			
		||||
| 
						 | 
				
			
			@ -204,30 +176,6 @@ static bool test_buffer(struct wlr_wl_backend *wl,
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dmabuf_listener_data {
 | 
			
		||||
	struct wl_buffer *wl_buffer;
 | 
			
		||||
	bool done;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void dmabuf_handle_created(void *data_, struct zwp_linux_buffer_params_v1 *params,
 | 
			
		||||
		struct wl_buffer *buffer) {
 | 
			
		||||
	struct dmabuf_listener_data *data = data_;
 | 
			
		||||
	data->wl_buffer = buffer;
 | 
			
		||||
	data->done = true;
 | 
			
		||||
	wlr_log(WLR_DEBUG, "DMA-BUF imported into parent Wayland compositor");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dmabuf_handle_failed(void *data_, struct zwp_linux_buffer_params_v1 *params) {
 | 
			
		||||
	struct dmabuf_listener_data *data = data_;
 | 
			
		||||
	data->done = true;
 | 
			
		||||
	wlr_log(WLR_ERROR, "Failed to import DMA-BUF into parent Wayland compositor");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct zwp_linux_buffer_params_v1_listener dmabuf_listener = {
 | 
			
		||||
	.created = dmabuf_handle_created,
 | 
			
		||||
	.failed = dmabuf_handle_failed,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl,
 | 
			
		||||
		struct wlr_dmabuf_attributes *dmabuf) {
 | 
			
		||||
	uint32_t modifier_hi = dmabuf->modifier >> 32;
 | 
			
		||||
| 
						 | 
				
			
			@ -239,35 +187,18 @@ static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl,
 | 
			
		|||
			dmabuf->offset[i], dmabuf->stride[i], modifier_hi, modifier_lo);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct dmabuf_listener_data data = {0};
 | 
			
		||||
	zwp_linux_buffer_params_v1_add_listener(params, &dmabuf_listener, &data);
 | 
			
		||||
	zwp_linux_buffer_params_v1_create(params, dmabuf->width, dmabuf->height, dmabuf->format, 0);
 | 
			
		||||
 | 
			
		||||
	struct wl_event_queue *display_queue =
 | 
			
		||||
		wl_proxy_get_queue((struct wl_proxy *)wl->remote_display);
 | 
			
		||||
	wl_proxy_set_queue((struct wl_proxy *)params, wl->busy_loop_queue);
 | 
			
		||||
 | 
			
		||||
	while (!data.done) {
 | 
			
		||||
		if (wl_display_dispatch_queue(wl->remote_display, wl->busy_loop_queue) < 0) {
 | 
			
		||||
			wlr_log(WLR_ERROR, "wl_display_dispatch_queue() failed");
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wl_buffer *buffer = data.wl_buffer;
 | 
			
		||||
	if (buffer != NULL) {
 | 
			
		||||
		wl_proxy_set_queue((struct wl_proxy *)buffer, display_queue);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wl_buffer *wl_buffer = zwp_linux_buffer_params_v1_create_immed(
 | 
			
		||||
		params, dmabuf->width, dmabuf->height, dmabuf->format, 0);
 | 
			
		||||
	zwp_linux_buffer_params_v1_destroy(params);
 | 
			
		||||
	return buffer;
 | 
			
		||||
	// TODO: handle create() errors
 | 
			
		||||
	return wl_buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wl_buffer *import_shm(struct wlr_wl_backend *wl,
 | 
			
		||||
		struct wlr_shm_attributes *shm) {
 | 
			
		||||
	enum wl_shm_format wl_shm_format = convert_drm_format_to_wl_shm(shm->format);
 | 
			
		||||
	uint32_t size = shm->stride * shm->height;
 | 
			
		||||
	struct wl_shm_pool *pool = wl_shm_create_pool(wl->shm, shm->fd, shm->offset + size);
 | 
			
		||||
	struct wl_shm_pool *pool = wl_shm_create_pool(wl->shm, shm->fd, size);
 | 
			
		||||
	if (pool == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -331,58 +262,6 @@ static struct wlr_wl_buffer *get_or_create_wl_buffer(struct wlr_wl_backend *wl,
 | 
			
		|||
	return create_wl_buffer(wl, wlr_buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void destroy_wl_drm_syncobj_timeline(struct wlr_wl_drm_syncobj_timeline *timeline) {
 | 
			
		||||
	wp_linux_drm_syncobj_timeline_v1_destroy(timeline->wl);
 | 
			
		||||
	wlr_addon_finish(&timeline->addon);
 | 
			
		||||
	wl_list_remove(&timeline->link);
 | 
			
		||||
	free(timeline);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void drm_syncobj_timeline_addon_destroy(struct wlr_addon *addon) {
 | 
			
		||||
	struct wlr_wl_drm_syncobj_timeline *timeline = wl_container_of(addon, timeline, addon);
 | 
			
		||||
	destroy_wl_drm_syncobj_timeline(timeline);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wlr_addon_interface drm_syncobj_timeline_addon_impl = {
 | 
			
		||||
	.name = "wlr_wl_drm_syncobj_timeline",
 | 
			
		||||
	.destroy = drm_syncobj_timeline_addon_destroy,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct wlr_wl_drm_syncobj_timeline *get_or_create_drm_syncobj_timeline(
 | 
			
		||||
		struct wlr_wl_backend *wl, struct wlr_drm_syncobj_timeline *wlr_timeline) {
 | 
			
		||||
	struct wlr_addon *addon =
 | 
			
		||||
		wlr_addon_find(&wlr_timeline->addons, wl, &drm_syncobj_timeline_addon_impl);
 | 
			
		||||
	if (addon != NULL) {
 | 
			
		||||
		struct wlr_wl_drm_syncobj_timeline *timeline = wl_container_of(addon, timeline, addon);
 | 
			
		||||
		return timeline;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_wl_drm_syncobj_timeline *timeline = calloc(1, sizeof(*timeline));
 | 
			
		||||
	if (timeline == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timeline->base = wlr_timeline;
 | 
			
		||||
 | 
			
		||||
	int fd = wlr_drm_syncobj_timeline_export(wlr_timeline);
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		free(timeline);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timeline->wl = wp_linux_drm_syncobj_manager_v1_import_timeline(wl->drm_syncobj_manager_v1, fd);
 | 
			
		||||
	close(fd);
 | 
			
		||||
	if (timeline->wl == NULL) {
 | 
			
		||||
		free(timeline);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_addon_init(&timeline->addon, &wlr_timeline->addons, wl, &drm_syncobj_timeline_addon_impl);
 | 
			
		||||
	wl_list_insert(&wl->drm_syncobj_timelines, &timeline->link);
 | 
			
		||||
 | 
			
		||||
	return timeline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool update_title(struct wlr_wl_output *output, const char *title) {
 | 
			
		||||
	struct wlr_output *wlr_output = &output->wlr_output;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -422,28 +301,6 @@ static bool output_test(struct wlr_output *wlr_output,
 | 
			
		|||
	struct wlr_wl_output *output =
 | 
			
		||||
		get_wl_output_from_output(wlr_output);
 | 
			
		||||
 | 
			
		||||
	if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
 | 
			
		||||
		// If the size doesn't match, reject buffer (scaling is not currently
 | 
			
		||||
		// supported but could be implemented with viewporter)
 | 
			
		||||
		int pending_width, pending_height;
 | 
			
		||||
		output_pending_resolution(wlr_output, state,
 | 
			
		||||
			&pending_width, &pending_height);
 | 
			
		||||
		if (state->buffer->width != pending_width ||
 | 
			
		||||
				state->buffer->height != pending_height) {
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Primary buffer size mismatch");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		// Source crop is also not currently supported
 | 
			
		||||
		struct wlr_fbox src_box;
 | 
			
		||||
		output_state_get_buffer_src_box(state, &src_box);
 | 
			
		||||
		if (src_box.x != 0.0 || src_box.y != 0.0 ||
 | 
			
		||||
				src_box.width != (double)state->buffer->width ||
 | 
			
		||||
				src_box.height != (double)state->buffer->height) {
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Source crop not supported in wayland output");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE;
 | 
			
		||||
	if (unsupported != 0) {
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32,
 | 
			
		||||
| 
						 | 
				
			
			@ -477,21 +334,6 @@ static bool output_test(struct wlr_output *wlr_output,
 | 
			
		|||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((state->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) &&
 | 
			
		||||
			!(state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE)) {
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Signal timeline requires a wait timeline");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) ||
 | 
			
		||||
			(state->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE)) {
 | 
			
		||||
		struct wlr_dmabuf_attributes dmabuf;
 | 
			
		||||
		if (!wlr_buffer_get_dmabuf(state->buffer, &dmabuf)) {
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Wait/signal timelines require DMA-BUFs");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (state->committed & WLR_OUTPUT_STATE_LAYERS) {
 | 
			
		||||
		// If we can't use a sub-surface for a layer, then we can't use a
 | 
			
		||||
		// sub-surface for any layer underneath
 | 
			
		||||
| 
						 | 
				
			
			@ -723,15 +565,15 @@ static const struct wl_callback_listener unmap_callback_listener = {
 | 
			
		|||
	.done = unmap_callback_handle_done,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output_state *state) {
 | 
			
		||||
	struct wlr_wl_output *output = get_wl_output_from_output(wlr_output);
 | 
			
		||||
static bool output_commit(struct wlr_output *wlr_output,
 | 
			
		||||
		const struct wlr_output_state *state) {
 | 
			
		||||
	struct wlr_wl_output *output =
 | 
			
		||||
		get_wl_output_from_output(wlr_output);
 | 
			
		||||
 | 
			
		||||
	if (!output_test(wlr_output, state)) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_wl_backend *wl = output->backend;
 | 
			
		||||
 | 
			
		||||
	bool pending_enabled = output_pending_enabled(wlr_output, state);
 | 
			
		||||
 | 
			
		||||
	if (wlr_output->enabled && !pending_enabled) {
 | 
			
		||||
| 
						 | 
				
			
			@ -756,28 +598,15 @@ static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output
 | 
			
		|||
		wl_surface_commit(output->surface);
 | 
			
		||||
		output->initialized = true;
 | 
			
		||||
 | 
			
		||||
		struct wl_event_queue *display_queue =
 | 
			
		||||
			wl_proxy_get_queue((struct wl_proxy *)wl->remote_display);
 | 
			
		||||
		wl_proxy_set_queue((struct wl_proxy *)output->xdg_surface, wl->busy_loop_queue);
 | 
			
		||||
		wl_proxy_set_queue((struct wl_proxy *)output->xdg_toplevel, wl->busy_loop_queue);
 | 
			
		||||
 | 
			
		||||
		wl_display_flush(wl->remote_display);
 | 
			
		||||
		wl_display_flush(output->backend->remote_display);
 | 
			
		||||
		while (!output->configured) {
 | 
			
		||||
			if (wl_display_dispatch_queue(wl->remote_display, wl->busy_loop_queue) == -1) {
 | 
			
		||||
				wlr_log(WLR_ERROR, "wl_display_dispatch_queue() failed");
 | 
			
		||||
				break;
 | 
			
		||||
			if (wl_display_dispatch(output->backend->remote_display) == -1) {
 | 
			
		||||
				wlr_log(WLR_ERROR, "wl_display_dispatch() failed");
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		wl_proxy_set_queue((struct wl_proxy *)output->xdg_surface, display_queue);
 | 
			
		||||
		wl_proxy_set_queue((struct wl_proxy *)output->xdg_toplevel, display_queue);
 | 
			
		||||
 | 
			
		||||
		if (!output->configured) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_wl_buffer *buffer = NULL;
 | 
			
		||||
	if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
 | 
			
		||||
		const pixman_region32_t *damage = NULL;
 | 
			
		||||
		if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
 | 
			
		||||
| 
						 | 
				
			
			@ -785,7 +614,8 @@ static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		struct wlr_buffer *wlr_buffer = state->buffer;
 | 
			
		||||
		buffer = get_or_create_wl_buffer(wl, wlr_buffer);
 | 
			
		||||
		struct wlr_wl_buffer *buffer =
 | 
			
		||||
			get_or_create_wl_buffer(output->backend, wlr_buffer);
 | 
			
		||||
		if (buffer == NULL) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -794,63 +624,6 @@ static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output
 | 
			
		|||
		damage_surface(output->surface, damage);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (state->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
 | 
			
		||||
		struct wlr_wl_drm_syncobj_timeline *wait_timeline =
 | 
			
		||||
			get_or_create_drm_syncobj_timeline(wl, state->wait_timeline);
 | 
			
		||||
 | 
			
		||||
		struct wlr_wl_drm_syncobj_timeline *signal_timeline;
 | 
			
		||||
		uint64_t signal_point;
 | 
			
		||||
		if (state->committed & WLR_OUTPUT_STATE_SIGNAL_TIMELINE) {
 | 
			
		||||
			signal_timeline = get_or_create_drm_syncobj_timeline(wl, state->signal_timeline);
 | 
			
		||||
			signal_point = state->signal_point;
 | 
			
		||||
		} else {
 | 
			
		||||
			if (buffer->fallback_signal_timeline == NULL) {
 | 
			
		||||
				buffer->fallback_signal_timeline =
 | 
			
		||||
					wlr_drm_syncobj_timeline_create(wl->drm_fd);
 | 
			
		||||
				if (buffer->fallback_signal_timeline == NULL) {
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			signal_timeline =
 | 
			
		||||
				get_or_create_drm_syncobj_timeline(wl, buffer->fallback_signal_timeline);
 | 
			
		||||
			signal_point = ++buffer->fallback_signal_point;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (wait_timeline == NULL || signal_timeline == NULL) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (output->drm_syncobj_surface_v1 == NULL) {
 | 
			
		||||
			output->drm_syncobj_surface_v1 = wp_linux_drm_syncobj_manager_v1_get_surface(
 | 
			
		||||
				wl->drm_syncobj_manager_v1, output->surface);
 | 
			
		||||
			if (output->drm_syncobj_surface_v1 == NULL) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		uint32_t wait_point_hi = state->wait_point >> 32;
 | 
			
		||||
		uint32_t wait_point_lo = state->wait_point & UINT32_MAX;
 | 
			
		||||
		uint32_t signal_point_hi = signal_point >> 32;
 | 
			
		||||
		uint32_t signal_point_lo = signal_point & UINT32_MAX;
 | 
			
		||||
 | 
			
		||||
		wp_linux_drm_syncobj_surface_v1_set_acquire_point(output->drm_syncobj_surface_v1,
 | 
			
		||||
			wait_timeline->wl, wait_point_hi, wait_point_lo);
 | 
			
		||||
		wp_linux_drm_syncobj_surface_v1_set_release_point(output->drm_syncobj_surface_v1,
 | 
			
		||||
			signal_timeline->wl, signal_point_hi, signal_point_lo);
 | 
			
		||||
 | 
			
		||||
		if (!wlr_drm_syncobj_timeline_waiter_init(&buffer->drm_syncobj_waiter,
 | 
			
		||||
				signal_timeline->base, signal_point, 0, wl->event_loop,
 | 
			
		||||
				buffer_handle_drm_syncobj_ready)) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		buffer->has_drm_syncobj_waiter = true;
 | 
			
		||||
	} else {
 | 
			
		||||
		if (output->drm_syncobj_surface_v1 != NULL) {
 | 
			
		||||
			wp_linux_drm_syncobj_surface_v1_destroy(output->drm_syncobj_surface_v1);
 | 
			
		||||
			output->drm_syncobj_surface_v1 = NULL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((state->committed & WLR_OUTPUT_STATE_LAYERS) &&
 | 
			
		||||
			!commit_layers(output, state->layers, state->layers_len)) {
 | 
			
		||||
		return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -864,8 +637,9 @@ static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output
 | 
			
		|||
		wl_callback_add_listener(output->frame_callback, &frame_listener, output);
 | 
			
		||||
 | 
			
		||||
		struct wp_presentation_feedback *wp_feedback = NULL;
 | 
			
		||||
		if (wl->presentation != NULL) {
 | 
			
		||||
			wp_feedback = wp_presentation_feedback(wl->presentation, output->surface);
 | 
			
		||||
		if (output->backend->presentation != NULL) {
 | 
			
		||||
			wp_feedback = wp_presentation_feedback(output->backend->presentation,
 | 
			
		||||
				output->surface);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (output->has_configure_serial) {
 | 
			
		||||
| 
						 | 
				
			
			@ -898,7 +672,7 @@ static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_display_flush(wl->remote_display);
 | 
			
		||||
	wl_display_flush(output->backend->remote_display);
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -954,8 +728,6 @@ static void output_destroy(struct wlr_output *wlr_output) {
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_output_finish(wlr_output);
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&output->link);
 | 
			
		||||
 | 
			
		||||
	if (output->cursor.surface) {
 | 
			
		||||
| 
						 | 
				
			
			@ -976,9 +748,6 @@ static void output_destroy(struct wlr_output *wlr_output) {
 | 
			
		|||
		wl_callback_destroy(output->unmap_callback);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (output->drm_syncobj_surface_v1) {
 | 
			
		||||
		wp_linux_drm_syncobj_surface_v1_destroy(output->drm_syncobj_surface_v1);
 | 
			
		||||
	}
 | 
			
		||||
	if (output->zxdg_toplevel_decoration_v1) {
 | 
			
		||||
		zxdg_toplevel_decoration_v1_destroy(output->zxdg_toplevel_decoration_v1);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1055,12 +824,6 @@ static void xdg_surface_handle_configure(void *data,
 | 
			
		|||
	output->has_configure_serial = true;
 | 
			
		||||
	output->configure_serial = serial;
 | 
			
		||||
 | 
			
		||||
	if (!output->wlr_output.enabled) {
 | 
			
		||||
		// We're waiting for a configure event after an initial commit to enable
 | 
			
		||||
		// the output. Do not notify the compositor about the requested state.
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_output_state state;
 | 
			
		||||
	wlr_output_state_init(&state);
 | 
			
		||||
	wlr_output_state_set_custom_mode(&state, req_width, req_height, 0);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
									
								
							
							
						
						
									
										258
									
								
								examples/fullscreen-shell.c
									
										
									
									
									
										Normal 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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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'],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
									
								
							
							
						
						
									
										13
									
								
								include/backend/backend.h
									
										
									
									
									
										Normal 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
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										9
									
								
								include/render/allocator/allocator.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								include/render/allocator/allocator.h
									
										
									
									
									
										Normal 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
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										15
									
								
								include/types/wlr_matrix.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								include/types/wlr_matrix.h
									
										
									
									
									
										Normal 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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -4,8 +4,6 @@
 | 
			
		|||
#include <stdint.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
static const long NSEC_PER_SEC = 1000000000;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get the current time, in milliseconds.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@
 | 
			
		|||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <wayland-server-core.h>
 | 
			
		||||
#include <wlr/util/addon.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A synchronization timeline.
 | 
			
		||||
| 
						 | 
				
			
			@ -30,24 +29,20 @@ struct wlr_drm_syncobj_timeline {
 | 
			
		|||
	int drm_fd;
 | 
			
		||||
	uint32_t handle;
 | 
			
		||||
 | 
			
		||||
	struct wlr_addon_set addons;
 | 
			
		||||
	// private state
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		size_t n_refs;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	size_t n_refs;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_drm_syncobj_timeline_waiter;
 | 
			
		||||
 | 
			
		||||
typedef void (*wlr_drm_syncobj_timeline_ready_callback)(
 | 
			
		||||
	struct wlr_drm_syncobj_timeline_waiter *waiter);
 | 
			
		||||
 | 
			
		||||
struct wlr_drm_syncobj_timeline_waiter {
 | 
			
		||||
	struct {
 | 
			
		||||
		int ev_fd;
 | 
			
		||||
		struct wl_event_source *event_source;
 | 
			
		||||
		wlr_drm_syncobj_timeline_ready_callback callback;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
		struct wl_signal ready;
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	// private state
 | 
			
		||||
 | 
			
		||||
	int ev_fd;
 | 
			
		||||
	struct wl_event_source *event_source;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -67,17 +62,6 @@ struct wlr_drm_syncobj_timeline *wlr_drm_syncobj_timeline_ref(struct wlr_drm_syn
 | 
			
		|||
 * Unreference a synchronization timeline.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_drm_syncobj_timeline_unref(struct wlr_drm_syncobj_timeline *timeline);
 | 
			
		||||
/**
 | 
			
		||||
 * Export a drm_syncobj FD from a timeline.
 | 
			
		||||
 */
 | 
			
		||||
int wlr_drm_syncobj_timeline_export(struct wlr_drm_syncobj_timeline *timeline);
 | 
			
		||||
/**
 | 
			
		||||
 * Transfer a point from a timeline to another.
 | 
			
		||||
 *
 | 
			
		||||
 * Both timelines must have been created with the same DRM FD.
 | 
			
		||||
 */
 | 
			
		||||
bool wlr_drm_syncobj_timeline_transfer(struct wlr_drm_syncobj_timeline *dst,
 | 
			
		||||
	uint64_t dst_point, struct wlr_drm_syncobj_timeline *src, uint64_t src_point);
 | 
			
		||||
/**
 | 
			
		||||
 * Check if a timeline point has been signalled or has materialized.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -94,12 +78,10 @@ bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline,
 | 
			
		|||
 * Asynchronously wait for a timeline point.
 | 
			
		||||
 *
 | 
			
		||||
 * See wlr_drm_syncobj_timeline_check() for a definition of flags.
 | 
			
		||||
 *
 | 
			
		||||
 * A callback must be provided that will be invoked when the waiter has finished.
 | 
			
		||||
 */
 | 
			
		||||
bool wlr_drm_syncobj_timeline_waiter_init(struct wlr_drm_syncobj_timeline_waiter *waiter,
 | 
			
		||||
	struct wlr_drm_syncobj_timeline *timeline, uint64_t point, uint32_t flags,
 | 
			
		||||
	struct wl_event_loop *loop, wlr_drm_syncobj_timeline_ready_callback callback);
 | 
			
		||||
	struct wl_event_loop *loop);
 | 
			
		||||
/**
 | 
			
		||||
 * Cancel a timeline waiter.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,10 +10,9 @@
 | 
			
		|||
struct wlr_swapchain_slot {
 | 
			
		||||
	struct wlr_buffer *buffer;
 | 
			
		||||
	bool acquired; // waiting for release
 | 
			
		||||
	int age;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener release;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	struct wl_listener release;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_swapchain {
 | 
			
		||||
| 
						 | 
				
			
			@ -24,9 +23,7 @@ struct wlr_swapchain {
 | 
			
		|||
 | 
			
		||||
	struct wlr_swapchain_slot slots[WLR_SWAPCHAIN_CAP];
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener allocator_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	struct wl_listener allocator_destroy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_swapchain *wlr_swapchain_create(
 | 
			
		||||
| 
						 | 
				
			
			@ -39,12 +36,21 @@ void wlr_swapchain_destroy(struct wlr_swapchain *swapchain);
 | 
			
		|||
 * The returned buffer is locked. When the caller is done with it, they must
 | 
			
		||||
 * unlock it by calling wlr_buffer_unlock.
 | 
			
		||||
 */
 | 
			
		||||
struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain);
 | 
			
		||||
struct wlr_buffer *wlr_swapchain_acquire(struct wlr_swapchain *swapchain,
 | 
			
		||||
	int *age);
 | 
			
		||||
/**
 | 
			
		||||
 * Returns true if this buffer has been created by this swapchain, and false
 | 
			
		||||
 * otherwise.
 | 
			
		||||
 */
 | 
			
		||||
bool wlr_swapchain_has_buffer(struct wlr_swapchain *swapchain,
 | 
			
		||||
	struct wlr_buffer *buffer);
 | 
			
		||||
/**
 | 
			
		||||
 * Mark the buffer as submitted for presentation. This needs to be called by
 | 
			
		||||
 * swap chain users on frame boundaries.
 | 
			
		||||
 *
 | 
			
		||||
 * If the buffer hasn't been created via the swap chain, the call is ignored.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_swapchain_set_buffer_submitted(struct wlr_swapchain *swapchain,
 | 
			
		||||
	struct wlr_buffer *buffer);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,25 +41,15 @@ struct wlr_renderer {
 | 
			
		|||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		/**
 | 
			
		||||
		 * Whether color transforms are supported for input textures
 | 
			
		||||
		 */
 | 
			
		||||
		bool input_color_transform;
 | 
			
		||||
		/**
 | 
			
		||||
		 * Does the renderer support color transforms on its output?
 | 
			
		||||
		 */
 | 
			
		||||
		bool output_color_transform;
 | 
			
		||||
		/**
 | 
			
		||||
		 * Whether wait/signal timelines are supported.
 | 
			
		||||
		 *
 | 
			
		||||
		 * See struct wlr_drm_syncobj_timeline.
 | 
			
		||||
		 */
 | 
			
		||||
		bool timeline;
 | 
			
		||||
	} features;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		const struct wlr_renderer_impl *impl;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	// private state
 | 
			
		||||
 | 
			
		||||
	const struct wlr_renderer_impl *impl;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,9 +20,9 @@ struct wlr_alpha_modifier_surface_v1_state {
 | 
			
		|||
struct wlr_alpha_modifier_v1 {
 | 
			
		||||
	struct wl_global *global;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener display_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	// private state
 | 
			
		||||
 | 
			
		||||
	struct wl_listener display_destroy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_alpha_modifier_v1 *wlr_alpha_modifier_v1_create(struct wl_display *display);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,15 +17,11 @@
 | 
			
		|||
struct wlr_buffer;
 | 
			
		||||
struct wlr_renderer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Shared-memory attributes for a buffer.
 | 
			
		||||
 */
 | 
			
		||||
struct wlr_shm_attributes {
 | 
			
		||||
	int fd;
 | 
			
		||||
	uint32_t format; // FourCC code, see DRM_FORMAT_* in <drm_fourcc.h>
 | 
			
		||||
	int width, height;
 | 
			
		||||
	int stride; // Number of bytes between consecutive pixel lines
 | 
			
		||||
	off_t offset; // Offset in bytes of the first pixel in FD
 | 
			
		||||
	uint32_t format;
 | 
			
		||||
	int width, height, stride;
 | 
			
		||||
	off_t offset;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -109,15 +105,6 @@ bool wlr_buffer_get_shm(struct wlr_buffer *buffer,
 | 
			
		|||
 */
 | 
			
		||||
struct wlr_buffer *wlr_buffer_try_from_resource(struct wl_resource *resource);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check whether a buffer is fully opaque.
 | 
			
		||||
 *
 | 
			
		||||
 * When true is returned, the buffer is guaranteed to be fully opaque, but the
 | 
			
		||||
 * reverse is not true: false may be returned in cases where the buffer is fully
 | 
			
		||||
 * opaque.
 | 
			
		||||
 */
 | 
			
		||||
bool wlr_buffer_is_opaque(struct wlr_buffer *buffer);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Buffer data pointer access flags.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -143,12 +130,6 @@ enum wlr_buffer_data_ptr_access_flag {
 | 
			
		|||
 */
 | 
			
		||||
bool wlr_buffer_begin_data_ptr_access(struct wlr_buffer *buffer, uint32_t flags,
 | 
			
		||||
	void **data, uint32_t *format, size_t *stride);
 | 
			
		||||
/**
 | 
			
		||||
 * Indicate that a pointer to a buffer's underlying memory will no longer be
 | 
			
		||||
 * used.
 | 
			
		||||
 *
 | 
			
		||||
 * This function must be called after wlr_buffer_begin_data_ptr_access().
 | 
			
		||||
 */
 | 
			
		||||
void wlr_buffer_end_data_ptr_access(struct wlr_buffer *buffer);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -167,12 +148,12 @@ struct wlr_client_buffer {
 | 
			
		|||
	 */
 | 
			
		||||
	struct wlr_buffer *source;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener source_destroy;
 | 
			
		||||
		struct wl_listener renderer_destroy;
 | 
			
		||||
	// private state
 | 
			
		||||
 | 
			
		||||
		size_t n_ignore_locks;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	struct wl_listener source_destroy;
 | 
			
		||||
	struct wl_listener renderer_destroy;
 | 
			
		||||
 | 
			
		||||
	size_t n_ignore_locks;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -181,29 +162,4 @@ struct wlr_client_buffer {
 | 
			
		|||
 */
 | 
			
		||||
struct wlr_client_buffer *wlr_client_buffer_get(struct wlr_buffer *buffer);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A single-pixel buffer.  Used by clients to draw solid-color rectangles.
 | 
			
		||||
 */
 | 
			
		||||
struct wlr_single_pixel_buffer_v1 {
 | 
			
		||||
	struct wlr_buffer base;
 | 
			
		||||
 | 
			
		||||
	// Full-scale for each component is UINT32_MAX
 | 
			
		||||
	uint32_t r, g, b, a;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_resource *resource;
 | 
			
		||||
		struct wl_listener release;
 | 
			
		||||
 | 
			
		||||
		// Packed little-endian DRM_FORMAT_ARGB8888. Used for data_ptr_access
 | 
			
		||||
		uint8_t argb8888[4];
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * If the wlr_buffer is a wlr_single_pixel_buffer_v1 then unwrap it.
 | 
			
		||||
 * Otherwise, returns NULL.
 | 
			
		||||
 */
 | 
			
		||||
struct wlr_single_pixel_buffer_v1 *wlr_single_pixel_buffer_v1_try_from_buffer(
 | 
			
		||||
	struct wlr_buffer *buffer);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -14,11 +14,10 @@
 | 
			
		|||
#include <stdint.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <wayland-server-core.h>
 | 
			
		||||
#include <wlr/types/wlr_output.h>
 | 
			
		||||
#include <wlr/util/addon.h>
 | 
			
		||||
#include <wlr/util/box.h>
 | 
			
		||||
 | 
			
		||||
struct wlr_surface;
 | 
			
		||||
 | 
			
		||||
enum wlr_surface_state_field {
 | 
			
		||||
	WLR_SURFACE_STATE_BUFFER = 1 << 0,
 | 
			
		||||
	WLR_SURFACE_STATE_SURFACE_DAMAGE = 1 << 1,
 | 
			
		||||
| 
						 | 
				
			
			@ -98,13 +97,6 @@ struct wlr_surface_role {
 | 
			
		|||
	 * such object exists.
 | 
			
		||||
	 */
 | 
			
		||||
	void (*commit)(struct wlr_surface *surface);
 | 
			
		||||
	/**
 | 
			
		||||
	 * Called when the surface is mapped. May be NULL.
 | 
			
		||||
	 *
 | 
			
		||||
	 * If the role is represented by an object, this is only called if
 | 
			
		||||
	 * such object exists.
 | 
			
		||||
	 */
 | 
			
		||||
	void (*map)(struct wlr_surface *surface);
 | 
			
		||||
	/**
 | 
			
		||||
	 * Called when the surface is unmapped. May be NULL.
 | 
			
		||||
	 *
 | 
			
		||||
| 
						 | 
				
			
			@ -123,11 +115,8 @@ struct wlr_surface_output {
 | 
			
		|||
	struct wlr_output *output;
 | 
			
		||||
 | 
			
		||||
	struct wl_list link; // wlr_surface.current_outputs
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener bind;
 | 
			
		||||
		struct wl_listener destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	struct wl_listener bind;
 | 
			
		||||
	struct wl_listener destroy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_surface {
 | 
			
		||||
| 
						 | 
				
			
			@ -191,47 +180,28 @@ struct wlr_surface {
 | 
			
		|||
	struct wl_resource *role_resource;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		/**
 | 
			
		||||
		 * Signals that the client has sent a wl_surface.commit request.
 | 
			
		||||
		 *
 | 
			
		||||
		 * The state to be committed can be accessed in wlr_surface.pending.
 | 
			
		||||
		 *
 | 
			
		||||
		 * The commit may not be applied immediately, in which case it's marked
 | 
			
		||||
		 * as "cached" and put into a queue. See wlr_surface_lock_pending().
 | 
			
		||||
		 */
 | 
			
		||||
		struct wl_signal client_commit;
 | 
			
		||||
		/**
 | 
			
		||||
		 * Signals that a commit has been applied.
 | 
			
		||||
		 *
 | 
			
		||||
		 * The new state can be accessed in wlr_surface.current.
 | 
			
		||||
		 */
 | 
			
		||||
		struct wl_signal commit;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Signals that the surface has a non-null buffer committed and is
 | 
			
		||||
		 * ready to be displayed.
 | 
			
		||||
		 * The `map` event signals that the surface has a non-null buffer
 | 
			
		||||
		 * committed and is ready to be displayed.
 | 
			
		||||
		 */
 | 
			
		||||
		struct wl_signal map;
 | 
			
		||||
		/**
 | 
			
		||||
		 * Signals that the surface shouldn't be displayed anymore. This can
 | 
			
		||||
		 * happen when a null buffer is committed, the associated role object
 | 
			
		||||
		 * is destroyed, or when the role-specific conditions for the surface
 | 
			
		||||
		 * to be mapped no longer apply.
 | 
			
		||||
		 * The `unmap` event signals that the surface shouldn't be displayed
 | 
			
		||||
		 * anymore. This can happen when a null buffer is committed,
 | 
			
		||||
		 * the associated role object is destroyed, or when the role-specific
 | 
			
		||||
		 * conditions for the surface to be mapped no longer apply.
 | 
			
		||||
		 */
 | 
			
		||||
		struct wl_signal unmap;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Signals that a new child sub-surface has been added.
 | 
			
		||||
		 *
 | 
			
		||||
		 * Note: unlike other new_* signals, new_subsurface is emitted when
 | 
			
		||||
		 * the subsurface is added to the parent surface's current state,
 | 
			
		||||
		 * not when the object is created.
 | 
			
		||||
		 */
 | 
			
		||||
		struct wl_signal new_subsurface; // struct wlr_subsurface
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Signals that the surface is being destroyed.
 | 
			
		||||
		 */
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -240,33 +210,33 @@ struct wlr_surface {
 | 
			
		|||
	struct wlr_addon_set addons;
 | 
			
		||||
	void *data;
 | 
			
		||||
 | 
			
		||||
	// private state
 | 
			
		||||
 | 
			
		||||
	struct wl_listener role_resource_destroy;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener role_resource_destroy;
 | 
			
		||||
		int32_t scale;
 | 
			
		||||
		enum wl_output_transform transform;
 | 
			
		||||
		int width, height;
 | 
			
		||||
		int buffer_width, buffer_height;
 | 
			
		||||
	} previous;
 | 
			
		||||
 | 
			
		||||
		struct {
 | 
			
		||||
			int32_t scale;
 | 
			
		||||
			enum wl_output_transform transform;
 | 
			
		||||
			int width, height;
 | 
			
		||||
			int buffer_width, buffer_height;
 | 
			
		||||
		} previous;
 | 
			
		||||
	bool unmap_commit;
 | 
			
		||||
 | 
			
		||||
		bool unmap_commit;
 | 
			
		||||
	bool opaque;
 | 
			
		||||
 | 
			
		||||
		bool opaque;
 | 
			
		||||
	bool handling_commit;
 | 
			
		||||
	bool pending_rejected;
 | 
			
		||||
 | 
			
		||||
		bool handling_commit;
 | 
			
		||||
		bool pending_rejected;
 | 
			
		||||
	int32_t preferred_buffer_scale;
 | 
			
		||||
	bool preferred_buffer_transform_sent;
 | 
			
		||||
	enum wl_output_transform preferred_buffer_transform;
 | 
			
		||||
 | 
			
		||||
		int32_t preferred_buffer_scale;
 | 
			
		||||
		bool preferred_buffer_transform_sent;
 | 
			
		||||
		enum wl_output_transform preferred_buffer_transform;
 | 
			
		||||
	struct wl_list synced; // wlr_surface_synced.link
 | 
			
		||||
	size_t synced_len;
 | 
			
		||||
 | 
			
		||||
		struct wl_list synced; // wlr_surface_synced.link
 | 
			
		||||
		size_t synced_len;
 | 
			
		||||
 | 
			
		||||
		struct wl_resource *pending_buffer_resource;
 | 
			
		||||
		struct wl_listener pending_buffer_resource_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	struct wl_resource *pending_buffer_resource;
 | 
			
		||||
	struct wl_listener pending_buffer_resource_destroy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_renderer;
 | 
			
		||||
| 
						 | 
				
			
			@ -275,15 +245,13 @@ struct wlr_compositor {
 | 
			
		|||
	struct wl_global *global;
 | 
			
		||||
	struct wlr_renderer *renderer; // may be NULL
 | 
			
		||||
 | 
			
		||||
	struct wl_listener display_destroy;
 | 
			
		||||
	struct wl_listener renderer_destroy;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_signal new_surface;
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener display_destroy;
 | 
			
		||||
		struct wl_listener renderer_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef void (*wlr_surface_iterator_func_t)(struct wlr_surface *surface,
 | 
			
		||||
| 
						 | 
				
			
			@ -413,7 +381,7 @@ void wlr_surface_send_frame_done(struct wlr_surface *surface,
 | 
			
		|||
 * surface coordinates.
 | 
			
		||||
 * X and y may be negative, if there are subsurfaces with negative position.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_surface_get_extents(struct wlr_surface *surface, struct wlr_box *box);
 | 
			
		||||
void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get the struct wlr_surface corresponding to a wl_surface resource.
 | 
			
		||||
| 
						 | 
				
			
			@ -485,8 +453,6 @@ void wlr_surface_set_preferred_buffer_scale(struct wlr_surface *surface,
 | 
			
		|||
void wlr_surface_set_preferred_buffer_transform(struct wlr_surface *surface,
 | 
			
		||||
	enum wl_output_transform transform);
 | 
			
		||||
 | 
			
		||||
struct wlr_surface_synced;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implementation for struct wlr_surface_synced.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -503,11 +469,6 @@ struct wlr_surface_synced_impl {
 | 
			
		|||
	void (*finish_state)(void *state);
 | 
			
		||||
	// Move a state. If NULL, memcpy() is used.
 | 
			
		||||
	void (*move_state)(void *dst, void *src);
 | 
			
		||||
 | 
			
		||||
	// Called when the state is committed. If NULL, this is a no-op.
 | 
			
		||||
	// If an object is a surface role object which has state synchronized with
 | 
			
		||||
	// the surface state, the role commit hook should be preferred over this.
 | 
			
		||||
	void (*commit)(struct wlr_surface_synced *synced);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
#define WLR_TYPES_WLR_CONTENT_TYPE_V1_H
 | 
			
		||||
 | 
			
		||||
#include <wayland-server-core.h>
 | 
			
		||||
#include <wayland-protocols/content-type-v1-enum.h>
 | 
			
		||||
#include "content-type-v1-protocol.h"
 | 
			
		||||
 | 
			
		||||
struct wlr_surface;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -23,9 +23,9 @@ struct wlr_content_type_manager_v1 {
 | 
			
		|||
 | 
			
		||||
	void *data;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener display_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	// private state
 | 
			
		||||
 | 
			
		||||
	struct wl_listener display_destroy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_content_type_manager_v1 *wlr_content_type_manager_v1_create(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
#define WLR_TYPES_WLR_CURSOR_SHAPE_V1_H
 | 
			
		||||
 | 
			
		||||
#include <wayland-server-core.h>
 | 
			
		||||
#include <wayland-protocols/cursor-shape-v1-enum.h>
 | 
			
		||||
#include "cursor-shape-v1-protocol.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Manager for the cursor-shape-v1 protocol.
 | 
			
		||||
| 
						 | 
				
			
			@ -28,9 +28,9 @@ struct wlr_cursor_shape_manager_v1 {
 | 
			
		|||
 | 
			
		||||
	void *data;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener display_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	// private state
 | 
			
		||||
 | 
			
		||||
	struct wl_listener display_destroy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum wlr_cursor_shape_manager_v1_device_type {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,27 +15,32 @@
 | 
			
		|||
#include <pixman.h>
 | 
			
		||||
#include <wayland-server-core.h>
 | 
			
		||||
 | 
			
		||||
/* For triple buffering, a history of two frames is required. */
 | 
			
		||||
#define WLR_DAMAGE_RING_PREVIOUS_LEN 2
 | 
			
		||||
 | 
			
		||||
struct wlr_box;
 | 
			
		||||
 | 
			
		||||
struct wlr_damage_ring_buffer {
 | 
			
		||||
	struct wlr_buffer *buffer;
 | 
			
		||||
	struct wl_listener destroy;
 | 
			
		||||
	pixman_region32_t damage;
 | 
			
		||||
 | 
			
		||||
	struct wlr_damage_ring *ring;
 | 
			
		||||
	struct wl_list link; // wlr_damage_ring.buffers
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_damage_ring {
 | 
			
		||||
	int32_t width, height;
 | 
			
		||||
 | 
			
		||||
	// Difference between the current buffer and the previous one
 | 
			
		||||
	pixman_region32_t current;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_list buffers; // wlr_damage_ring_buffer.link
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	// private state
 | 
			
		||||
 | 
			
		||||
	pixman_region32_t previous[WLR_DAMAGE_RING_PREVIOUS_LEN];
 | 
			
		||||
	size_t previous_idx;
 | 
			
		||||
 | 
			
		||||
	struct wl_list buffers; // wlr_damage_ring_buffer.link
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void wlr_damage_ring_init(struct wlr_damage_ring *ring);
 | 
			
		||||
| 
						 | 
				
			
			@ -43,17 +48,30 @@ void wlr_damage_ring_init(struct wlr_damage_ring *ring);
 | 
			
		|||
void wlr_damage_ring_finish(struct wlr_damage_ring *ring);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add a region to the current damage. The region must be in the buffer-local
 | 
			
		||||
 * coordinate space.
 | 
			
		||||
 * Set ring bounds and damage the ring fully.
 | 
			
		||||
 *
 | 
			
		||||
 * Next time damage will be added, it will be cropped to the ring bounds.
 | 
			
		||||
 * If at least one of the dimensions is 0, bounds are removed.
 | 
			
		||||
 *
 | 
			
		||||
 * By default, a damage ring doesn't have bounds.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_damage_ring_add(struct wlr_damage_ring *ring,
 | 
			
		||||
void wlr_damage_ring_set_bounds(struct wlr_damage_ring *ring,
 | 
			
		||||
	int32_t width, int32_t height);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add a region to the current damage.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns true if the region intersects the ring bounds, false otherwise.
 | 
			
		||||
 */
 | 
			
		||||
bool wlr_damage_ring_add(struct wlr_damage_ring *ring,
 | 
			
		||||
	const pixman_region32_t *damage);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add a box to the current damage. The box must be in the buffer-local
 | 
			
		||||
 * coordinate space.
 | 
			
		||||
 * Add a box to the current damage.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns true if the box intersects the ring bounds, false otherwise.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
 | 
			
		||||
bool wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
 | 
			
		||||
	const struct wlr_box *box);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +79,20 @@ void wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
 | 
			
		|||
 */
 | 
			
		||||
void wlr_damage_ring_add_whole(struct wlr_damage_ring *ring);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Rotate the damage ring. This needs to be called after using the accumulated
 | 
			
		||||
 * damage, e.g. after rendering to an output's back buffer.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_damage_ring_rotate(struct wlr_damage_ring *ring);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get accumulated damage, which is the difference between the current buffer
 | 
			
		||||
 * and the buffer with age of buffer_age; in context of rendering, this is
 | 
			
		||||
 * the region that needs to be redrawn.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring,
 | 
			
		||||
	int buffer_age, pixman_region32_t *damage);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get accumulated buffer damage and rotate the damage ring.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -70,8 +102,6 @@ void wlr_damage_ring_add_whole(struct wlr_damage_ring *ring);
 | 
			
		|||
 *
 | 
			
		||||
 * Users should damage the ring if an error occurs while rendering or
 | 
			
		||||
 * submitting the new buffer to the backend.
 | 
			
		||||
 *
 | 
			
		||||
 * The returned damage will be in the buffer-local coordinate space.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_damage_ring_rotate_buffer(struct wlr_damage_ring *ring,
 | 
			
		||||
	struct wlr_buffer *buffer, pixman_region32_t *damage);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,12 +12,6 @@
 | 
			
		|||
#include <wayland-server-core.h>
 | 
			
		||||
#include <wlr/types/wlr_seat.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Deprecated: this protocol is legacy and superseded by ext-data-control-v1.
 | 
			
		||||
 * The implementation will be dropped in a future wlroots version.
 | 
			
		||||
 *
 | 
			
		||||
 * Consider using `wlr_ext_data_control_manager_v1` as a replacement.
 | 
			
		||||
 */
 | 
			
		||||
struct wlr_data_control_manager_v1 {
 | 
			
		||||
	struct wl_global *global;
 | 
			
		||||
	struct wl_list devices; // wlr_data_control_device_v1.link
 | 
			
		||||
| 
						 | 
				
			
			@ -27,9 +21,7 @@ struct wlr_data_control_manager_v1 {
 | 
			
		|||
		struct wl_signal new_device; // wlr_data_control_device_v1
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener display_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	struct wl_listener display_destroy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_data_control_device_v1 {
 | 
			
		||||
| 
						 | 
				
			
			@ -41,11 +33,9 @@ struct wlr_data_control_device_v1 {
 | 
			
		|||
	struct wl_resource *selection_offer_resource; // current selection offer
 | 
			
		||||
	struct wl_resource *primary_selection_offer_resource; // current primary selection offer
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener seat_destroy;
 | 
			
		||||
		struct wl_listener seat_set_selection;
 | 
			
		||||
		struct wl_listener seat_set_primary_selection;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	struct wl_listener seat_destroy;
 | 
			
		||||
	struct wl_listener seat_set_selection;
 | 
			
		||||
	struct wl_listener seat_set_primary_selection;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_data_control_manager_v1 *wlr_data_control_manager_v1_create(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,15 +16,13 @@ struct wlr_data_device_manager {
 | 
			
		|||
	struct wl_global *global;
 | 
			
		||||
	struct wl_list data_sources;
 | 
			
		||||
 | 
			
		||||
	struct wl_listener display_destroy;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	void *data;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener display_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum wlr_data_offer_type {
 | 
			
		||||
| 
						 | 
				
			
			@ -42,9 +40,7 @@ struct wlr_data_offer {
 | 
			
		|||
	enum wl_data_device_manager_dnd_action preferred_action;
 | 
			
		||||
	bool in_ask;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener source_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	struct wl_listener source_destroy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -93,11 +89,9 @@ struct wlr_drag_icon {
 | 
			
		|||
		struct wl_signal destroy;
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	void *data;
 | 
			
		||||
	struct wl_listener surface_destroy;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener surface_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	void *data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum wlr_drag_grab_type {
 | 
			
		||||
| 
						 | 
				
			
			@ -130,14 +124,11 @@ struct wlr_drag {
 | 
			
		|||
		struct wl_signal destroy;
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	void *data;
 | 
			
		||||
	struct wl_listener source_destroy;
 | 
			
		||||
	struct wl_listener seat_client_destroy;
 | 
			
		||||
	struct wl_listener icon_destroy;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener source_destroy;
 | 
			
		||||
		struct wl_listener seat_client_destroy;
 | 
			
		||||
		struct wl_listener focus_destroy;
 | 
			
		||||
		struct wl_listener icon_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	void *data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_drag_motion_event {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,9 +21,7 @@ struct wlr_drm_buffer {
 | 
			
		|||
	struct wl_resource *resource; // can be NULL if the client destroyed it
 | 
			
		||||
	struct wlr_dmabuf_attributes dmabuf;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener release;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	struct wl_listener release;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -42,12 +40,12 @@ struct wlr_drm {
 | 
			
		|||
		struct wl_signal destroy;
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		char *node_name;
 | 
			
		||||
		struct wlr_drm_format_set formats;
 | 
			
		||||
	// private state
 | 
			
		||||
 | 
			
		||||
		struct wl_listener display_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	char *node_name;
 | 
			
		||||
	struct wlr_drm_format_set formats;
 | 
			
		||||
 | 
			
		||||
	struct wl_listener display_destroy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_drm_buffer *wlr_drm_buffer_try_from_resource(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,10 +18,9 @@ struct wlr_drm_lease_v1_manager {
 | 
			
		|||
	struct wl_list devices; // wlr_drm_lease_device_v1.link
 | 
			
		||||
 | 
			
		||||
	struct wl_display *display;
 | 
			
		||||
	struct wl_listener display_destroy;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Upon receiving this signal, call
 | 
			
		||||
		 * wlr_drm_lease_device_v1_grant_lease_request() to grant a lease of the
 | 
			
		||||
| 
						 | 
				
			
			@ -30,10 +29,6 @@ struct wlr_drm_lease_v1_manager {
 | 
			
		|||
		 */
 | 
			
		||||
		struct wl_signal request;
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener display_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_drm_lease_device_v1 {
 | 
			
		||||
| 
						 | 
				
			
			@ -48,11 +43,9 @@ struct wlr_drm_lease_device_v1 {
 | 
			
		|||
	struct wl_list requests; // wlr_drm_lease_request_v1.link
 | 
			
		||||
	struct wl_list link; // wlr_drm_lease_v1_manager.devices
 | 
			
		||||
 | 
			
		||||
	void *data;
 | 
			
		||||
	struct wl_listener backend_destroy;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener backend_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	void *data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_drm_lease_v1;
 | 
			
		||||
| 
						 | 
				
			
			@ -62,12 +55,12 @@ struct wlr_drm_lease_connector_v1 {
 | 
			
		|||
 | 
			
		||||
	struct wlr_output *output;
 | 
			
		||||
	struct wlr_drm_lease_device_v1 *device;
 | 
			
		||||
	/** NULL if no client is currently leasing this connector */
 | 
			
		||||
	struct wlr_drm_lease_v1 *active_lease;
 | 
			
		||||
 | 
			
		||||
	struct wl_listener destroy;
 | 
			
		||||
 | 
			
		||||
	struct wl_list link; // wlr_drm_lease_device_v1.connectors
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_drm_lease_request_v1 {
 | 
			
		||||
| 
						 | 
				
			
			@ -91,13 +84,14 @@ struct wlr_drm_lease_v1 {
 | 
			
		|||
 | 
			
		||||
	struct wlr_drm_lease_device_v1 *device;
 | 
			
		||||
 | 
			
		||||
	struct wlr_drm_lease_connector_v1 **connectors;
 | 
			
		||||
	size_t n_connectors;
 | 
			
		||||
 | 
			
		||||
	struct wl_list link; // wlr_drm_lease_device_v1.leases
 | 
			
		||||
 | 
			
		||||
	void *data;
 | 
			
		||||
	struct wl_listener destroy;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	void *data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,13 +17,11 @@ struct wlr_export_dmabuf_manager_v1 {
 | 
			
		|||
	struct wl_global *global;
 | 
			
		||||
	struct wl_list frames; // wlr_export_dmabuf_frame_v1.link
 | 
			
		||||
 | 
			
		||||
	struct wl_listener display_destroy;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener display_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_export_dmabuf_frame_v1 {
 | 
			
		||||
| 
						 | 
				
			
			@ -35,10 +33,8 @@ struct wlr_export_dmabuf_frame_v1 {
 | 
			
		|||
 | 
			
		||||
	bool cursor_locked;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener output_commit;
 | 
			
		||||
		struct wl_listener output_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	struct wl_listener output_commit;
 | 
			
		||||
	struct wl_listener output_destroy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_export_dmabuf_manager_v1 *wlr_export_dmabuf_manager_v1_create(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue