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.19.0" have entirely different histories.
		
	
	
		
	
		
					 111 changed files with 847 additions and 3581 deletions
				
			
		| 
						 | 
				
			
			@ -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 ]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -485,10 +485,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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,6 @@
 | 
			
		|||
#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[] = {
 | 
			
		||||
| 
						 | 
				
			
			@ -178,85 +177,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 +251,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;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -381,25 +295,11 @@ 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,7 +314,6 @@ 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -429,8 +328,6 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) {
 | 
			
		|||
			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,7 +337,6 @@ 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) {
 | 
			
		||||
| 
						 | 
				
			
			@ -532,12 +428,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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,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"
 | 
			
		||||
#include "util/env.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -38,12 +37,11 @@ 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_SIGNAL_TIMELINE;
 | 
			
		||||
 | 
			
		||||
static const uint32_t SUPPORTED_OUTPUT_STATE =
 | 
			
		||||
	WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE;
 | 
			
		||||
| 
						 | 
				
			
			@ -858,19 +856,6 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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 we're running as a secondary GPU, we can't perform an atomic
 | 
			
		||||
		// commit without blitting a buffer.
 | 
			
		||||
| 
						 | 
				
			
			@ -1717,11 +1702,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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +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,
 | 
			
		||||
| 
						 | 
				
			
			@ -125,17 +124,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;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,10 +22,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) },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,7 +37,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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -367,10 +367,7 @@ void wlr_session_close_file(struct wlr_session *session,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	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.
 | 
			
		||||
	assert(wl_list_empty(&dev->events.remove.listener_list));
 | 
			
		||||
 | 
			
		||||
	close(dev->fd);
 | 
			
		||||
	wl_list_remove(&dev->link);
 | 
			
		||||
| 
						 | 
				
			
			@ -519,6 +516,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 +533,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 +554,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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,6 +55,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 +75,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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -158,8 +158,6 @@ struct wlr_drm_connector_state {
 | 
			
		|||
	uint32_t fb_damage_clips;
 | 
			
		||||
	int primary_in_fence_fd, out_fence_fd;
 | 
			
		||||
	bool vrr_enabled;
 | 
			
		||||
	uint32_t colorspace;
 | 
			
		||||
	uint32_t hdr_output_metadata;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -214,10 +212,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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,10 +6,8 @@
 | 
			
		|||
#include <wlr/util/addon.h>
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
| 
						 | 
				
			
			@ -19,65 +17,32 @@ struct wlr_color_transform {
 | 
			
		|||
	enum wlr_color_transform_type type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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 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³.
 | 
			
		||||
 *
 | 
			
		||||
 * The offset of a color value for a given channel and color index is:
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 *     offset = channel_index * dim + color_index
 | 
			
		||||
 * 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_lut_3x1d {
 | 
			
		||||
struct wlr_color_transform_lut3d {
 | 
			
		||||
	struct wlr_color_transform base;
 | 
			
		||||
 | 
			
		||||
	uint16_t *lut_3x1d;
 | 
			
		||||
	size_t dim;
 | 
			
		||||
	float *lut_3d;
 | 
			
		||||
	size_t dim_len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 * Gets a wlr_color_transform_lut3d from a generic wlr_color_transform.
 | 
			
		||||
 * Asserts that the base type is COLOR_TRANSFORM_LUT_3D
 | 
			
		||||
 */
 | 
			
		||||
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_lut3d *wlr_color_transform_lut3d_from_base(
 | 
			
		||||
	struct wlr_color_transform *tr);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			@ -152,9 +151,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 +161,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 +191,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 +209,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 {
 | 
			
		||||
| 
						 | 
				
			
			@ -357,15 +334,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 +342,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 +356,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);
 | 
			
		||||
| 
						 | 
				
			
			@ -413,19 +381,14 @@ 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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -490,12 +453,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
 | 
			
		||||
| 
						 | 
				
			
			@ -504,7 +468,7 @@ struct wlr_vk_texture {
 | 
			
		|||
	struct wlr_buffer *buffer;
 | 
			
		||||
	struct wlr_addon buffer_addon;
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
| 
						 | 
				
			
			@ -552,7 +516,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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +25,6 @@ void output_defer_present(struct wlr_output *output, struct wlr_output_event_pre
 | 
			
		|||
 | 
			
		||||
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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -10,7 +10,6 @@
 | 
			
		|||
#define WLR_RENDER_COLOR_H
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -27,60 +26,6 @@ enum wlr_color_named_primaries {
 | 
			
		|||
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,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -128,25 +73,10 @@ 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.
 | 
			
		||||
| 
						 | 
				
			
			@ -159,10 +89,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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,12 +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.
 | 
			
		||||
	 *
 | 
			
		||||
| 
						 | 
				
			
			@ -103,10 +99,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.
 | 
			
		||||
	 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,10 +41,6 @@ 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?
 | 
			
		||||
		 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,11 +9,11 @@
 | 
			
		|||
#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 <wayland-server.h>
 | 
			
		||||
#include <wlr/render/color.h>
 | 
			
		||||
 | 
			
		||||
#include "color-management-v1-protocol.h"
 | 
			
		||||
 | 
			
		||||
struct wlr_surface;
 | 
			
		||||
 | 
			
		||||
struct wlr_image_description_v1_data {
 | 
			
		||||
| 
						 | 
				
			
			@ -58,10 +58,6 @@ struct wlr_color_manager_v1_options {
 | 
			
		|||
struct wlr_color_manager_v1 {
 | 
			
		||||
	struct wl_global *global;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wlr_color_manager_v1_features features;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -93,30 +89,4 @@ 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
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,6 +62,8 @@ 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_list link; // wlr_drm_lease_device_v1.connectors
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -91,6 +93,9 @@ 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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,9 +21,7 @@ struct wlr_ext_data_control_manager_v1 {
 | 
			
		|||
		struct wl_signal new_device; // wlr_ext_data_control_device_v1
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener display_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
	struct wl_listener display_destroy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_ext_data_control_device_v1 {
 | 
			
		||||
| 
						 | 
				
			
			@ -35,11 +33,9 @@ struct wlr_ext_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_ext_data_control_manager_v1 *wlr_ext_data_control_manager_v1_create(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,10 +13,6 @@
 | 
			
		|||
#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.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -83,31 +79,6 @@ struct wlr_ext_output_image_capture_source_manager_v1 {
 | 
			
		|||
	} 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.
 | 
			
		||||
| 
						 | 
				
			
			@ -120,15 +91,4 @@ struct wlr_ext_image_capture_source_v1 *wlr_ext_image_capture_source_v1_from_res
 | 
			
		|||
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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,9 +10,9 @@
 | 
			
		|||
#define WLR_TYPES_WLR_EXT_IMAGE_COPY_CAPTURE_V1_H
 | 
			
		||||
 | 
			
		||||
#include <pixman.h>
 | 
			
		||||
#include <wayland-server-protocol.h>
 | 
			
		||||
#include <wayland-protocols/ext-image-copy-capture-v1-enum.h>
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include "ext-image-copy-capture-v1-protocol.h"
 | 
			
		||||
 | 
			
		||||
struct wlr_renderer;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,28 +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_FIXES_H
 | 
			
		||||
#define WLR_TYPES_WLR_FIXES_H
 | 
			
		||||
 | 
			
		||||
#include <wayland-server-core.h>
 | 
			
		||||
 | 
			
		||||
struct wlr_fixes {
 | 
			
		||||
	struct wl_global *global;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener display_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_fixes *wlr_fixes_create(struct wl_display *display, uint32_t version);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -10,11 +10,6 @@ struct wlr_gamma_control_manager_v1 {
 | 
			
		|||
	struct wl_global *global;
 | 
			
		||||
	struct wl_list controls; // wlr_gamma_control_v1.link
 | 
			
		||||
 | 
			
		||||
	// Fallback to use when an struct wlr_output doesn't support gamma LUTs.
 | 
			
		||||
	// Can be used to apply gamma LUTs via a struct wlr_renderer. Leave zero to
 | 
			
		||||
	// indicate that the fallback is unsupported.
 | 
			
		||||
	size_t fallback_gamma_size;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
		struct wl_signal set_gamma; // struct wlr_gamma_control_manager_v1_set_gamma_event
 | 
			
		||||
| 
						 | 
				
			
			@ -54,8 +49,6 @@ struct wlr_gamma_control_v1 *wlr_gamma_control_manager_v1_get_control(
 | 
			
		|||
	struct wlr_gamma_control_manager_v1 *manager, struct wlr_output *output);
 | 
			
		||||
bool wlr_gamma_control_v1_apply(struct wlr_gamma_control_v1 *gamma_control,
 | 
			
		||||
	struct wlr_output_state *output_state);
 | 
			
		||||
struct wlr_color_transform *wlr_gamma_control_v1_get_color_transform(
 | 
			
		||||
	struct wlr_gamma_control_v1 *gamma_control);
 | 
			
		||||
void wlr_gamma_control_v1_send_failed_and_destroy(struct wlr_gamma_control_v1 *gamma_control);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,10 +48,10 @@ struct wlr_input_method_v2 {
 | 
			
		|||
	struct wl_list link;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_signal commit;
 | 
			
		||||
		struct wl_signal commit; // struct wlr_input_method_v2
 | 
			
		||||
		struct wl_signal new_popup_surface; // struct wlr_input_popup_surface_v2
 | 
			
		||||
		struct wl_signal grab_keyboard; // struct wlr_input_method_keyboard_grab_v2
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
		struct wl_signal destroy; // struct wlr_input_method_v2
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -94,8 +94,8 @@ struct wlr_input_method_manager_v2 {
 | 
			
		|||
	struct wl_list input_methods; // struct wlr_input_method_v2.link
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_signal new_input_method; // struct wlr_input_method_v2
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
		struct wl_signal input_method; // struct wlr_input_method_v2
 | 
			
		||||
		struct wl_signal destroy; // struct wlr_input_method_manager_v2
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,14 +16,12 @@
 | 
			
		|||
#include <wlr/types/wlr_input_device.h>
 | 
			
		||||
#include <xkbcommon/xkbcommon.h>
 | 
			
		||||
 | 
			
		||||
#define WLR_LED_COUNT 5
 | 
			
		||||
#define WLR_LED_COUNT 3
 | 
			
		||||
 | 
			
		||||
enum wlr_keyboard_led {
 | 
			
		||||
	WLR_LED_NUM_LOCK = 1 << 0,
 | 
			
		||||
	WLR_LED_CAPS_LOCK = 1 << 1,
 | 
			
		||||
	WLR_LED_SCROLL_LOCK = 1 << 2,
 | 
			
		||||
	WLR_LED_COMPOSE = 1 << 3,
 | 
			
		||||
	WLR_LED_KANA = 1 << 4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define WLR_MODIFIER_COUNT 8
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,6 @@
 | 
			
		|||
#include <time.h>
 | 
			
		||||
#include <wayland-server-protocol.h>
 | 
			
		||||
#include <wayland-util.h>
 | 
			
		||||
#include <wlr/render/color.h>
 | 
			
		||||
#include <wlr/render/wlr_renderer.h>
 | 
			
		||||
#include <wlr/types/wlr_buffer.h>
 | 
			
		||||
#include <wlr/util/addon.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -69,13 +68,12 @@ enum wlr_output_state_field {
 | 
			
		|||
	WLR_OUTPUT_STATE_SCALE = 1 << 4,
 | 
			
		||||
	WLR_OUTPUT_STATE_TRANSFORM = 1 << 5,
 | 
			
		||||
	WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED = 1 << 6,
 | 
			
		||||
	WLR_OUTPUT_STATE_RENDER_FORMAT = 1 << 7,
 | 
			
		||||
	WLR_OUTPUT_STATE_SUBPIXEL = 1 << 8,
 | 
			
		||||
	WLR_OUTPUT_STATE_LAYERS = 1 << 9,
 | 
			
		||||
	WLR_OUTPUT_STATE_WAIT_TIMELINE = 1 << 10,
 | 
			
		||||
	WLR_OUTPUT_STATE_SIGNAL_TIMELINE = 1 << 11,
 | 
			
		||||
	WLR_OUTPUT_STATE_COLOR_TRANSFORM = 1 << 12,
 | 
			
		||||
	WLR_OUTPUT_STATE_IMAGE_DESCRIPTION = 1 << 13,
 | 
			
		||||
	WLR_OUTPUT_STATE_GAMMA_LUT = 1 << 7,
 | 
			
		||||
	WLR_OUTPUT_STATE_RENDER_FORMAT = 1 << 8,
 | 
			
		||||
	WLR_OUTPUT_STATE_SUBPIXEL = 1 << 9,
 | 
			
		||||
	WLR_OUTPUT_STATE_LAYERS = 1 << 10,
 | 
			
		||||
	WLR_OUTPUT_STATE_WAIT_TIMELINE = 1 << 11,
 | 
			
		||||
	WLR_OUTPUT_STATE_SIGNAL_TIMELINE = 1 << 12,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum wlr_output_state_mode_type {
 | 
			
		||||
| 
						 | 
				
			
			@ -83,30 +81,6 @@ enum wlr_output_state_mode_type {
 | 
			
		|||
	WLR_OUTPUT_STATE_MODE_CUSTOM,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Colorimetric image description.
 | 
			
		||||
 *
 | 
			
		||||
 * Carries information about the color encoding used for a struct wlr_buffer.
 | 
			
		||||
 *
 | 
			
		||||
 * Supported primaries are advertised in wlr_output.supported_primaries.
 | 
			
		||||
 * Supported transfer functions are advertised in
 | 
			
		||||
 * wlr_output.supported_transfer_functions.
 | 
			
		||||
 *
 | 
			
		||||
 * mastering_display_primaries, mastering_luminance, max_cll and max_fall are
 | 
			
		||||
 * optional. Luminances are given in cd/m².
 | 
			
		||||
 */
 | 
			
		||||
struct wlr_output_image_description {
 | 
			
		||||
	enum wlr_color_named_primaries primaries;
 | 
			
		||||
	enum wlr_color_transfer_function transfer_function;
 | 
			
		||||
 | 
			
		||||
	struct wlr_color_primaries mastering_display_primaries;
 | 
			
		||||
	struct {
 | 
			
		||||
		double min, max;
 | 
			
		||||
	} mastering_luminance;
 | 
			
		||||
	double max_cll; // max content light level
 | 
			
		||||
	double max_fall; // max frame-average light level
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Holds the double-buffered output state.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -148,6 +122,9 @@ struct wlr_output_state {
 | 
			
		|||
		int32_t refresh; // mHz, may be zero
 | 
			
		||||
	} custom_mode;
 | 
			
		||||
 | 
			
		||||
	uint16_t *gamma_lut;
 | 
			
		||||
	size_t gamma_lut_size;
 | 
			
		||||
 | 
			
		||||
	struct wlr_output_layer_state *layers;
 | 
			
		||||
	size_t layers_len;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -155,10 +132,6 @@ struct wlr_output_state {
 | 
			
		|||
	uint64_t wait_point;
 | 
			
		||||
	struct wlr_drm_syncobj_timeline *signal_timeline;
 | 
			
		||||
	uint64_t signal_point;
 | 
			
		||||
 | 
			
		||||
	struct wlr_color_transform *color_transform;
 | 
			
		||||
 | 
			
		||||
	struct wlr_output_image_description *image_description;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_output_impl;
 | 
			
		||||
| 
						 | 
				
			
			@ -194,16 +167,12 @@ struct wlr_output {
 | 
			
		|||
	int32_t width, height;
 | 
			
		||||
	int32_t refresh; // mHz, may be zero
 | 
			
		||||
 | 
			
		||||
	uint32_t supported_primaries; // bitfield of enum wlr_color_named_primaries
 | 
			
		||||
	uint32_t supported_transfer_functions; // bitfield of enum wlr_color_transfer_function
 | 
			
		||||
 | 
			
		||||
	bool enabled;
 | 
			
		||||
	float scale;
 | 
			
		||||
	enum wl_output_subpixel subpixel;
 | 
			
		||||
	enum wl_output_transform transform;
 | 
			
		||||
	enum wlr_output_adaptive_sync_status adaptive_sync_status;
 | 
			
		||||
	uint32_t render_format;
 | 
			
		||||
	const struct wlr_output_image_description *image_description;
 | 
			
		||||
 | 
			
		||||
	// Indicates whether making changes to adaptive sync status is supported.
 | 
			
		||||
	// If false, changes to adaptive sync status is guaranteed to fail. If
 | 
			
		||||
| 
						 | 
				
			
			@ -266,8 +235,6 @@ struct wlr_output {
 | 
			
		|||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener display_destroy;
 | 
			
		||||
		struct wlr_output_image_description image_description_value;
 | 
			
		||||
		struct wlr_color_transform *color_transform;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -278,13 +245,13 @@ struct wlr_output_event_damage {
 | 
			
		|||
 | 
			
		||||
struct wlr_output_event_precommit {
 | 
			
		||||
	struct wlr_output *output;
 | 
			
		||||
	struct timespec when;
 | 
			
		||||
	struct timespec *when;
 | 
			
		||||
	const struct wlr_output_state *state;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_output_event_commit {
 | 
			
		||||
	struct wlr_output *output;
 | 
			
		||||
	struct timespec when;
 | 
			
		||||
	struct timespec *when;
 | 
			
		||||
	const struct wlr_output_state *state;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -560,6 +527,17 @@ void wlr_output_state_set_subpixel(struct wlr_output_state *state,
 | 
			
		|||
 */
 | 
			
		||||
void wlr_output_state_set_buffer(struct wlr_output_state *state,
 | 
			
		||||
	struct wlr_buffer *buffer);
 | 
			
		||||
/**
 | 
			
		||||
 * Sets the gamma table for an output. `r`, `g` and `b` are gamma ramps for
 | 
			
		||||
 * red, green and blue. `size` is the length of the ramps and must not exceed
 | 
			
		||||
 * the value returned by wlr_output_get_gamma_size().
 | 
			
		||||
 *
 | 
			
		||||
 * Providing zero-sized ramps resets the gamma table.
 | 
			
		||||
 *
 | 
			
		||||
 * This state will be applied once wlr_output_commit_state() is called.
 | 
			
		||||
 */
 | 
			
		||||
bool wlr_output_state_set_gamma_lut(struct wlr_output_state *state,
 | 
			
		||||
	size_t ramp_size, const uint16_t *r, const uint16_t *g, const uint16_t *b);
 | 
			
		||||
/**
 | 
			
		||||
 * Sets the damage region for an output. This is used as a hint to the backend
 | 
			
		||||
 * and can be used to reduce power consumption or increase performance on some
 | 
			
		||||
| 
						 | 
				
			
			@ -608,19 +586,6 @@ void wlr_output_state_set_wait_timeline(struct wlr_output_state *state,
 | 
			
		|||
 */
 | 
			
		||||
void wlr_output_state_set_signal_timeline(struct wlr_output_state *state,
 | 
			
		||||
	struct wlr_drm_syncobj_timeline *timeline, uint64_t dst_point);
 | 
			
		||||
/**
 | 
			
		||||
 * Set the color transform for an output.
 | 
			
		||||
 *
 | 
			
		||||
 * The color transform is applied after blending output layers.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_output_state_set_color_transform(struct wlr_output_state *state,
 | 
			
		||||
	struct wlr_color_transform *tr);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Set the colorimetry image description.
 | 
			
		||||
 */
 | 
			
		||||
bool wlr_output_state_set_image_description(struct wlr_output_state *state,
 | 
			
		||||
	const struct wlr_output_image_description *image_desc);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Copies the output state from src to dst. It is safe to then
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,10 +11,10 @@
 | 
			
		|||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <wayland-server-core.h>
 | 
			
		||||
#include <wayland-protocols/pointer-constraints-unstable-v1-enum.h>
 | 
			
		||||
#include <pixman.h>
 | 
			
		||||
#include <wlr/types/wlr_compositor.h>
 | 
			
		||||
#include <wlr/types/wlr_seat.h>
 | 
			
		||||
#include "pointer-constraints-unstable-v1-protocol.h"
 | 
			
		||||
 | 
			
		||||
struct wlr_seat;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,7 +43,6 @@ struct wlr_scene_output_layout;
 | 
			
		|||
struct wlr_presentation;
 | 
			
		||||
struct wlr_linux_dmabuf_v1;
 | 
			
		||||
struct wlr_gamma_control_manager_v1;
 | 
			
		||||
struct wlr_color_manager_v1;
 | 
			
		||||
struct wlr_output_state;
 | 
			
		||||
 | 
			
		||||
typedef bool (*wlr_scene_buffer_point_accepts_input_func_t)(
 | 
			
		||||
| 
						 | 
				
			
			@ -103,13 +102,11 @@ struct wlr_scene {
 | 
			
		|||
	// May be NULL
 | 
			
		||||
	struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1;
 | 
			
		||||
	struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1;
 | 
			
		||||
	struct wlr_color_manager_v1 *color_manager_v1;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener linux_dmabuf_v1_destroy;
 | 
			
		||||
		struct wl_listener gamma_control_manager_v1_destroy;
 | 
			
		||||
		struct wl_listener gamma_control_manager_v1_set_gamma;
 | 
			
		||||
		struct wl_listener color_manager_v1_destroy;
 | 
			
		||||
 | 
			
		||||
		enum wlr_scene_debug_damage_option debug_damage_option;
 | 
			
		||||
		bool direct_scanout;
 | 
			
		||||
| 
						 | 
				
			
			@ -126,10 +123,6 @@ struct wlr_scene_surface {
 | 
			
		|||
	struct {
 | 
			
		||||
		struct wlr_box clip;
 | 
			
		||||
 | 
			
		||||
		// Output used for frame pacing (surface frame callbacks, presentation
 | 
			
		||||
		// time feedback, etc), may be NULL
 | 
			
		||||
		struct wlr_output *frame_pacing_output;
 | 
			
		||||
 | 
			
		||||
		struct wlr_addon addon;
 | 
			
		||||
 | 
			
		||||
		struct wl_listener outputs_update;
 | 
			
		||||
| 
						 | 
				
			
			@ -159,11 +152,6 @@ struct wlr_scene_output_sample_event {
 | 
			
		|||
	bool direct_scanout;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_scene_frame_done_event {
 | 
			
		||||
	struct wlr_scene_output *output;
 | 
			
		||||
	struct timespec when;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** A scene-graph node displaying a buffer */
 | 
			
		||||
struct wlr_scene_buffer {
 | 
			
		||||
	struct wlr_scene_node node;
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +164,7 @@ struct wlr_scene_buffer {
 | 
			
		|||
		struct wl_signal output_enter; // struct wlr_scene_output
 | 
			
		||||
		struct wl_signal output_leave; // struct wlr_scene_output
 | 
			
		||||
		struct wl_signal output_sample; // struct wlr_scene_output_sample_event
 | 
			
		||||
		struct wl_signal frame_done; // struct wlr_scene_frame_done_event
 | 
			
		||||
		struct wl_signal frame_done; // struct timespec
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	// May be NULL
 | 
			
		||||
| 
						 | 
				
			
			@ -185,7 +173,8 @@ struct wlr_scene_buffer {
 | 
			
		|||
	/**
 | 
			
		||||
	 * The output that the largest area of this buffer is displayed on.
 | 
			
		||||
	 * This may be NULL if the buffer is not currently displayed on any
 | 
			
		||||
	 * outputs.
 | 
			
		||||
	 * outputs. This is the output that should be used for frame callbacks,
 | 
			
		||||
	 * presentation feedback, etc.
 | 
			
		||||
	 */
 | 
			
		||||
	struct wlr_scene_output *primary_output;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -195,8 +184,6 @@ struct wlr_scene_buffer {
 | 
			
		|||
	int dst_width, dst_height;
 | 
			
		||||
	enum wl_output_transform transform;
 | 
			
		||||
	pixman_region32_t opaque_region;
 | 
			
		||||
	enum wlr_color_transfer_function transfer_function;
 | 
			
		||||
	enum wlr_color_named_primaries primaries;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		uint64_t active_outputs;
 | 
			
		||||
| 
						 | 
				
			
			@ -252,11 +239,6 @@ struct wlr_scene_output {
 | 
			
		|||
 | 
			
		||||
		bool gamma_lut_changed;
 | 
			
		||||
		struct wlr_gamma_control_v1 *gamma_lut;
 | 
			
		||||
		struct wlr_color_transform *gamma_lut_color_transform;
 | 
			
		||||
 | 
			
		||||
		struct wlr_color_transform *prev_gamma_lut_color_transform;
 | 
			
		||||
		struct wlr_color_transform *prev_supplied_color_transform;
 | 
			
		||||
		struct wlr_color_transform *prev_combined_color_transform;
 | 
			
		||||
 | 
			
		||||
		struct wl_listener output_commit;
 | 
			
		||||
		struct wl_listener output_damage;
 | 
			
		||||
| 
						 | 
				
			
			@ -374,13 +356,6 @@ void wlr_scene_set_linux_dmabuf_v1(struct wlr_scene *scene,
 | 
			
		|||
void wlr_scene_set_gamma_control_manager_v1(struct wlr_scene *scene,
 | 
			
		||||
	struct wlr_gamma_control_manager_v1 *gamma_control);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handles color_management_v1 feedback for all surfaces in the scene.
 | 
			
		||||
 *
 | 
			
		||||
 * Asserts that a struct wlr_color_manager_v1 hasn't already been set for the scene.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_scene_set_color_manager_v1(struct wlr_scene *scene, struct wlr_color_manager_v1 *manager);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add a node displaying nothing but its children.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -441,12 +416,6 @@ struct wlr_scene_rect *wlr_scene_rect_from_node(struct wlr_scene_node *node);
 | 
			
		|||
struct wlr_scene_surface *wlr_scene_surface_try_from_buffer(
 | 
			
		||||
	struct wlr_scene_buffer *scene_buffer);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Call wlr_surface_send_frame_done() if the surface is visible.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_scene_surface_send_frame_done(struct wlr_scene_surface *scene_surface,
 | 
			
		||||
	const struct timespec *when);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add a node displaying a solid-colored rectangle to the scene-graph.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -558,17 +527,11 @@ void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer,
 | 
			
		|||
void wlr_scene_buffer_set_filter_mode(struct wlr_scene_buffer *scene_buffer,
 | 
			
		||||
	enum wlr_scale_filter_mode filter_mode);
 | 
			
		||||
 | 
			
		||||
void wlr_scene_buffer_set_transfer_function(struct wlr_scene_buffer *scene_buffer,
 | 
			
		||||
	enum wlr_color_transfer_function transfer_function);
 | 
			
		||||
 | 
			
		||||
void wlr_scene_buffer_set_primaries(struct wlr_scene_buffer *scene_buffer,
 | 
			
		||||
	enum wlr_color_named_primaries primaries);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Calls the buffer's frame_done signal.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer,
 | 
			
		||||
	struct wlr_scene_frame_done_event *event);
 | 
			
		||||
	struct timespec *now);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add a viewport for the specified output to the scene-graph.
 | 
			
		||||
| 
						 | 
				
			
			@ -589,11 +552,6 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output,
 | 
			
		|||
 | 
			
		||||
struct wlr_scene_output_state_options {
 | 
			
		||||
	struct wlr_scene_timer *timer;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Color transform to apply before the output's color transform. Cannot be
 | 
			
		||||
	 * used when the output has a non-NULL image description set.
 | 
			
		||||
	 */
 | 
			
		||||
	struct wlr_color_transform *color_transform;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,13 +14,6 @@
 | 
			
		|||
#include <wlr/types/wlr_buffer.h>
 | 
			
		||||
#include <wlr/util/box.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Deprecated: this protocol is deprecated and superseded by ext-image-copy-capture-v1.
 | 
			
		||||
 * The implementation will be dropped in a future wlroots version.
 | 
			
		||||
 *
 | 
			
		||||
 * Consider using `wlr_ext_image_capture_source_v1` instead.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct wlr_screencopy_manager_v1 {
 | 
			
		||||
	struct wl_global *global;
 | 
			
		||||
	struct wl_list frames; // wlr_screencopy_frame_v1.link
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,9 +10,10 @@
 | 
			
		|||
#define WLR_TYPES_WLR_TABLET_V2_H
 | 
			
		||||
 | 
			
		||||
#include <wayland-server-core.h>
 | 
			
		||||
#include <wayland-protocols/tablet-v2-enum.h>
 | 
			
		||||
#include <wlr/types/wlr_seat.h>
 | 
			
		||||
 | 
			
		||||
#include "tablet-v2-protocol.h"
 | 
			
		||||
 | 
			
		||||
/* This can probably be even lower,the tools don't have a lot of buttons */
 | 
			
		||||
#define WLR_TABLET_V2_TOOL_BUTTONS_CAP 16
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,9 +11,11 @@
 | 
			
		|||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <wayland-server-core.h>
 | 
			
		||||
#include <wayland-protocols/tearing-control-v1-enum.h>
 | 
			
		||||
#include <wayland-server-protocol.h>
 | 
			
		||||
#include <wlr/types/wlr_compositor.h>
 | 
			
		||||
 | 
			
		||||
#include "tearing-control-v1-protocol.h"
 | 
			
		||||
 | 
			
		||||
struct wlr_tearing_control_v1 {
 | 
			
		||||
	struct wl_client *client;
 | 
			
		||||
	struct wl_list link;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,10 +57,10 @@ struct wlr_text_input_v3 {
 | 
			
		|||
	struct wl_list link;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_signal enable;
 | 
			
		||||
		struct wl_signal commit;
 | 
			
		||||
		struct wl_signal disable;
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
		struct wl_signal enable; // struct wlr_text_input_v3
 | 
			
		||||
		struct wl_signal commit; // struct wlr_text_input_v3
 | 
			
		||||
		struct wl_signal disable; // struct wlr_text_input_v3
 | 
			
		||||
		struct wl_signal destroy; // struct wlr_text_input_v3
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -74,8 +74,8 @@ struct wlr_text_input_manager_v3 {
 | 
			
		|||
	struct wl_list text_inputs; // wlr_text_input_v3.link
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_signal new_text_input; // struct wlr_text_input_v3
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
		struct wl_signal text_input; // struct wlr_text_input_v3
 | 
			
		||||
		struct wl_signal destroy; // struct wlr_text_input_manager_v3
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,10 +10,10 @@
 | 
			
		|||
#define WLR_TYPES_WLR_XDG_SHELL_H
 | 
			
		||||
 | 
			
		||||
#include <wayland-server-core.h>
 | 
			
		||||
#include <wayland-protocols/xdg-shell-enum.h>
 | 
			
		||||
#include <wlr/types/wlr_compositor.h>
 | 
			
		||||
#include <wlr/types/wlr_seat.h>
 | 
			
		||||
#include <wlr/util/box.h>
 | 
			
		||||
#include "xdg-shell-protocol.h"
 | 
			
		||||
 | 
			
		||||
struct wlr_xdg_shell {
 | 
			
		||||
	struct wl_global *global;
 | 
			
		||||
| 
						 | 
				
			
			@ -141,7 +141,6 @@ enum wlr_xdg_surface_role {
 | 
			
		|||
struct wlr_xdg_toplevel_state {
 | 
			
		||||
	bool maximized, fullscreen, resizing, activated, suspended;
 | 
			
		||||
	uint32_t tiled; // enum wlr_edges
 | 
			
		||||
	uint32_t constrained; // enum wlr_edges
 | 
			
		||||
	int32_t width, height;
 | 
			
		||||
	int32_t max_width, max_height;
 | 
			
		||||
	int32_t min_width, min_height;
 | 
			
		||||
| 
						 | 
				
			
			@ -169,7 +168,6 @@ struct wlr_xdg_toplevel_configure {
 | 
			
		|||
	// The following fields must always be set to reflect the current state
 | 
			
		||||
	bool maximized, fullscreen, resizing, activated, suspended;
 | 
			
		||||
	uint32_t tiled; // enum wlr_edges
 | 
			
		||||
	uint32_t constrained; // enum wlr_edges
 | 
			
		||||
	int32_t width, height;
 | 
			
		||||
 | 
			
		||||
	// Only for WLR_XDG_TOPLEVEL_CONFIGURE_BOUNDS
 | 
			
		||||
| 
						 | 
				
			
			@ -456,14 +454,6 @@ uint32_t wlr_xdg_toplevel_set_wm_capabilities(struct wlr_xdg_toplevel *toplevel,
 | 
			
		|||
uint32_t wlr_xdg_toplevel_set_suspended(struct wlr_xdg_toplevel *toplevel,
 | 
			
		||||
		bool suspended);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Request that this toplevel consider itself constrained and doesn't attempt to
 | 
			
		||||
 * resize from some edges. `constrained_edges` is a bitfield of enum wlr_edges.
 | 
			
		||||
 * Returns the associated configure serial.
 | 
			
		||||
 */
 | 
			
		||||
uint32_t wlr_xdg_toplevel_set_constrained(struct wlr_xdg_toplevel *toplevel,
 | 
			
		||||
		uint32_t constrained_edges);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Request that this toplevel closes.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,41 +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_XDG_TOPLEVEL_TAG_V1_H
 | 
			
		||||
#define WLR_TYPES_WLR_XDG_TOPLEVEL_TAG_V1_H
 | 
			
		||||
 | 
			
		||||
#include <wayland-server-core.h>
 | 
			
		||||
 | 
			
		||||
struct wlr_xdg_toplevel_tag_manager_v1 {
 | 
			
		||||
	struct wl_global *global;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_signal set_tag; // struct wlr_xdg_toplevel_tag_manager_v1_set_tag_event
 | 
			
		||||
		struct wl_signal set_description; // struct wlr_xdg_toplevel_tag_manager_v1_set_description_event
 | 
			
		||||
		struct wl_signal destroy;
 | 
			
		||||
	} events;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct wl_listener display_destroy;
 | 
			
		||||
	} WLR_PRIVATE;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_xdg_toplevel_tag_manager_v1_set_tag_event {
 | 
			
		||||
	struct wlr_xdg_toplevel *toplevel;
 | 
			
		||||
	const char *tag;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_xdg_toplevel_tag_manager_v1_set_description_event {
 | 
			
		||||
	struct wlr_xdg_toplevel *toplevel;
 | 
			
		||||
	const char *description;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_xdg_toplevel_tag_manager_v1 *wlr_xdg_toplevel_tag_manager_v1_create(
 | 
			
		||||
	struct wl_display *display, uint32_t version);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -146,6 +146,7 @@ struct wlr_xwayland_surface {
 | 
			
		|||
	char *role;
 | 
			
		||||
	char *startup_id;
 | 
			
		||||
	pid_t pid;
 | 
			
		||||
	bool has_utf8_title;
 | 
			
		||||
 | 
			
		||||
	struct wl_list children; // wlr_xwayland_surface.parent_link
 | 
			
		||||
	struct wlr_xwayland_surface *parent;
 | 
			
		||||
| 
						 | 
				
			
			@ -221,7 +222,6 @@ struct wlr_xwayland_surface {
 | 
			
		|||
		struct wl_signal set_override_redirect;
 | 
			
		||||
		struct wl_signal set_geometry;
 | 
			
		||||
		struct wl_signal set_opacity;
 | 
			
		||||
		struct wl_signal set_icon;
 | 
			
		||||
		struct wl_signal focus_in;
 | 
			
		||||
		struct wl_signal grab_focus;
 | 
			
		||||
		/* can be used to set initial maximized/fullscreen geometry */
 | 
			
		||||
| 
						 | 
				
			
			@ -402,15 +402,6 @@ enum wlr_xwayland_icccm_input_model wlr_xwayland_surface_icccm_input_model(
 | 
			
		|||
void wlr_xwayland_set_workareas(struct wlr_xwayland *wlr_xwayland,
 | 
			
		||||
	const struct wlr_box *workareas, size_t num_workareas);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fetches the icon set via the _NET_WM_ICON property.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns true on success. The caller is responsible for freeing the reply
 | 
			
		||||
 * using xcb_ewmh_get_wm_icon_reply_wipe().
 | 
			
		||||
 */
 | 
			
		||||
bool wlr_xwayland_surface_fetch_icon(
 | 
			
		||||
	const struct wlr_xwayland_surface *xsurface,
 | 
			
		||||
	xcb_ewmh_get_wm_icon_reply_t *icon_reply);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get the XCB connection of the XWM.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,7 +36,6 @@ enum atom_name {
 | 
			
		|||
	NET_WM_STATE,
 | 
			
		||||
	NET_WM_STRUT_PARTIAL,
 | 
			
		||||
	NET_WM_WINDOW_TYPE,
 | 
			
		||||
	NET_WM_ICON,
 | 
			
		||||
	WM_TAKE_FOCUS,
 | 
			
		||||
	WINDOW,
 | 
			
		||||
	NET_ACTIVE_WINDOW,
 | 
			
		||||
| 
						 | 
				
			
			@ -116,7 +115,6 @@ struct wlr_xwm {
 | 
			
		|||
	xcb_connection_t *xcb_conn;
 | 
			
		||||
	xcb_screen_t *screen;
 | 
			
		||||
	xcb_window_t window;
 | 
			
		||||
	xcb_window_t no_focus_window;
 | 
			
		||||
	xcb_visualid_t visual_id;
 | 
			
		||||
	xcb_colormap_t colormap;
 | 
			
		||||
	xcb_render_pictformat_t render_format_id;
 | 
			
		||||
| 
						 | 
				
			
			@ -164,7 +162,6 @@ struct wlr_xwm {
 | 
			
		|||
	struct wl_listener drop_focus_destroy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// xwm_create takes ownership of wm_fd and will close it under all circumstances.
 | 
			
		||||
struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland, int wm_fd);
 | 
			
		||||
 | 
			
		||||
void xwm_destroy(struct wlr_xwm *xwm);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
project(
 | 
			
		||||
	'wlroots',
 | 
			
		||||
	'c',
 | 
			
		||||
	version: '0.20.0-dev',
 | 
			
		||||
	version: '0.19.0',
 | 
			
		||||
	license: 'MIT',
 | 
			
		||||
	meson_version: '>=1.3',
 | 
			
		||||
	default_options: [
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +86,7 @@ internal_features = {
 | 
			
		|||
internal_config = configuration_data()
 | 
			
		||||
 | 
			
		||||
wayland_kwargs = {
 | 
			
		||||
	'version': '>=1.24.0',
 | 
			
		||||
	'version': '>=1.23.1',
 | 
			
		||||
	'fallback': 'wayland',
 | 
			
		||||
	'default_options': [
 | 
			
		||||
		'tests=false',
 | 
			
		||||
| 
						 | 
				
			
			@ -105,8 +105,8 @@ drm = dependency('libdrm',
 | 
			
		|||
		'tests=false',
 | 
			
		||||
	],
 | 
			
		||||
)
 | 
			
		||||
xkbcommon = dependency('xkbcommon',
 | 
			
		||||
	version: '>=1.8.0',
 | 
			
		||||
xkbcommon = dependency(
 | 
			
		||||
	'xkbcommon',
 | 
			
		||||
	fallback: 'libxkbcommon',
 | 
			
		||||
	default_options: [
 | 
			
		||||
		'enable-tools=false',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,9 @@
 | 
			
		|||
wayland_protos = dependency('wayland-protocols',
 | 
			
		||||
	version: '>=1.44',
 | 
			
		||||
	version: '>=1.41',
 | 
			
		||||
	fallback: 'wayland-protocols',
 | 
			
		||||
	default_options: ['tests=false'],
 | 
			
		||||
)
 | 
			
		||||
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
 | 
			
		||||
wlr_deps += wayland_protos
 | 
			
		||||
 | 
			
		||||
wayland_scanner_dep = dependency('wayland-scanner',
 | 
			
		||||
	kwargs: wayland_kwargs,
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +25,6 @@ protocols = {
 | 
			
		|||
	# Staging upstream protocols
 | 
			
		||||
	'alpha-modifier-v1': wl_protocol_dir / 'staging/alpha-modifier/alpha-modifier-v1.xml',
 | 
			
		||||
	'color-management-v1': wl_protocol_dir / 'staging/color-management/color-management-v1.xml',
 | 
			
		||||
	'color-representation-v1': wl_protocol_dir / 'staging/color-representation/color-representation-v1.xml',
 | 
			
		||||
	'content-type-v1': wl_protocol_dir / 'staging/content-type/content-type-v1.xml',
 | 
			
		||||
	'cursor-shape-v1': wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
 | 
			
		||||
	'drm-lease-v1': wl_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml',
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +42,6 @@ protocols = {
 | 
			
		|||
	'xdg-dialog-v1': wl_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
 | 
			
		||||
	'xdg-system-bell-v1': wl_protocol_dir / 'staging/xdg-system-bell/xdg-system-bell-v1.xml',
 | 
			
		||||
	'xdg-toplevel-icon-v1': wl_protocol_dir / 'staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml',
 | 
			
		||||
	'xdg-toplevel-tag-v1': wl_protocol_dir / 'staging/xdg-toplevel-tag/xdg-toplevel-tag-v1.xml',
 | 
			
		||||
	'xwayland-shell-v1': wl_protocol_dir / 'staging/xwayland-shell/xwayland-shell-v1.xml',
 | 
			
		||||
	'tearing-control-v1': wl_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,7 +43,7 @@
 | 
			
		|||
 | 
			
		||||
    <request name="capture_output">
 | 
			
		||||
      <description summary="capture a frame from an output">
 | 
			
		||||
        Capture the next frame of an entire output.
 | 
			
		||||
        Capture the next frame of a an entire output.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="frame" type="new_id" interface="zwlr_export_dmabuf_frame_v1"/>
 | 
			
		||||
      <arg name="overlay_cursor" type="int"
 | 
			
		||||
| 
						 | 
				
			
			@ -136,7 +136,7 @@
 | 
			
		|||
      <arg name="stride" type="uint"
 | 
			
		||||
           summary="line size in bytes"/>
 | 
			
		||||
      <arg name="plane_index" type="uint"
 | 
			
		||||
           summary="index of the plane the data in the object applies to"/>
 | 
			
		||||
           summary="index of the the plane the data in the object applies to"/>
 | 
			
		||||
    </event>
 | 
			
		||||
 | 
			
		||||
    <event name="ready">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,7 +58,7 @@
 | 
			
		|||
      </description>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <event name="finished" type="destructor">
 | 
			
		||||
    <event name="finished">
 | 
			
		||||
      <description summary="the compositor has finished with the toplevel manager">
 | 
			
		||||
        This event indicates that the compositor is done sending events to the
 | 
			
		||||
        zwlr_foreign_toplevel_manager_v1. The server will destroy the object
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,7 +72,7 @@
 | 
			
		|||
      tables. At any time the compositor can send a failed event indicating that
 | 
			
		||||
      this object is no longer valid.
 | 
			
		||||
 | 
			
		||||
      There can only be at most one gamma control object per output, which
 | 
			
		||||
      There must always be at most one gamma control object per output, which
 | 
			
		||||
      has exclusive access to this particular output. When the gamma control
 | 
			
		||||
      object is destroyed, the gamma table is restored to its original value.
 | 
			
		||||
    </description>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -156,8 +156,8 @@
 | 
			
		|||
        not assume that the name is a reflection of an underlying DRM
 | 
			
		||||
        connector, X11 connection, etc.
 | 
			
		||||
 | 
			
		||||
        If this head matches a wl_output, the wl_output.name event must report
 | 
			
		||||
        the same name.
 | 
			
		||||
        If the compositor implements the xdg-output protocol and this head is
 | 
			
		||||
        enabled, the xdg_output.name event must report the same name.
 | 
			
		||||
 | 
			
		||||
        The name event is sent after a wlr_output_head object is created. This
 | 
			
		||||
        event is only sent once per object, and the name does not change over
 | 
			
		||||
| 
						 | 
				
			
			@ -176,8 +176,8 @@
 | 
			
		|||
        the make, model, serial of the underlying DRM connector or the display
 | 
			
		||||
        name of the underlying X11 connection, etc.
 | 
			
		||||
 | 
			
		||||
        If this head matches a wl_output, the wl_output.description event must
 | 
			
		||||
        report the same name.
 | 
			
		||||
        If the compositor implements xdg-output and this head is enabled,
 | 
			
		||||
        the xdg_output.description must report the same description.
 | 
			
		||||
 | 
			
		||||
        The description event is sent after a wlr_output_head object is created.
 | 
			
		||||
        This event is only sent once per object, and the description does not
 | 
			
		||||
| 
						 | 
				
			
			@ -191,10 +191,6 @@
 | 
			
		|||
        This event describes the physical size of the head. This event is only
 | 
			
		||||
        sent if the head has a physical size (e.g. is not a projector or a
 | 
			
		||||
        virtual device).
 | 
			
		||||
 | 
			
		||||
        The physical size event is sent after a wlr_output_head object is created. This
 | 
			
		||||
        event is only sent once per object, and the physical size does not change over
 | 
			
		||||
        the lifetime of the wlr_output_head object.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="width" type="int" summary="width in millimeters of the output"/>
 | 
			
		||||
      <arg name="height" type="int" summary="height in millimeters of the output"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -268,6 +264,9 @@
 | 
			
		|||
      <description summary="head manufacturer">
 | 
			
		||||
        This event describes the manufacturer of the head.
 | 
			
		||||
 | 
			
		||||
        This must report the same make as the wl_output interface does in its
 | 
			
		||||
        geometry event.
 | 
			
		||||
 | 
			
		||||
        Together with the model and serial_number events the purpose is to
 | 
			
		||||
        allow clients to recognize heads from previous sessions and for example
 | 
			
		||||
        load head-specific configurations back.
 | 
			
		||||
| 
						 | 
				
			
			@ -279,10 +278,6 @@
 | 
			
		|||
        identify the head by available information from other events but should
 | 
			
		||||
        be aware that there is an increased risk of false positives.
 | 
			
		||||
 | 
			
		||||
        If sent, the make event is sent after a wlr_output_head object is
 | 
			
		||||
        created and only sent once per object. The make does not change over
 | 
			
		||||
        the lifetime of the wlr_output_head object.
 | 
			
		||||
 | 
			
		||||
        It is not recommended to display the make string in UI to users. For
 | 
			
		||||
        that the string provided by the description event should be preferred.
 | 
			
		||||
      </description>
 | 
			
		||||
| 
						 | 
				
			
			@ -293,6 +288,9 @@
 | 
			
		|||
      <description summary="head model">
 | 
			
		||||
        This event describes the model of the head.
 | 
			
		||||
 | 
			
		||||
        This must report the same model as the wl_output interface does in its
 | 
			
		||||
        geometry event.
 | 
			
		||||
 | 
			
		||||
        Together with the make and serial_number events the purpose is to
 | 
			
		||||
        allow clients to recognize heads from previous sessions and for example
 | 
			
		||||
        load head-specific configurations back.
 | 
			
		||||
| 
						 | 
				
			
			@ -304,10 +302,6 @@
 | 
			
		|||
        identify the head by available information from other events but should
 | 
			
		||||
        be aware that there is an increased risk of false positives.
 | 
			
		||||
 | 
			
		||||
        If sent, the model event is sent after a wlr_output_head object is
 | 
			
		||||
        created and only sent once per object. The model does not change over
 | 
			
		||||
        the lifetime of the wlr_output_head object.
 | 
			
		||||
 | 
			
		||||
        It is not recommended to display the model string in UI to users. For
 | 
			
		||||
        that the string provided by the description event should be preferred.
 | 
			
		||||
      </description>
 | 
			
		||||
| 
						 | 
				
			
			@ -329,10 +323,6 @@
 | 
			
		|||
        available information from other events but should be aware that there
 | 
			
		||||
        is an increased risk of false positives.
 | 
			
		||||
 | 
			
		||||
        If sent, the serial number event is sent after a wlr_output_head object
 | 
			
		||||
        is created and only sent once per object. The serial number does not
 | 
			
		||||
        change over the lifetime of the wlr_output_head object.
 | 
			
		||||
 | 
			
		||||
        It is not recommended to display the serial_number string in UI to
 | 
			
		||||
        users. For that the string provided by the description event should be
 | 
			
		||||
        preferred.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,7 @@
 | 
			
		|||
 | 
			
		||||
    <request name="get_output_power">
 | 
			
		||||
      <description summary="get a power management for an output">
 | 
			
		||||
        Create an output power management mode control that can be used to
 | 
			
		||||
        Create a output power management mode control that can be used to
 | 
			
		||||
        adjust the power management mode for a given output.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="id" type="new_id" interface="zwlr_output_power_v1"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +79,7 @@
 | 
			
		|||
    </enum>
 | 
			
		||||
 | 
			
		||||
    <enum name="error">
 | 
			
		||||
      <entry name="invalid_mode" value="1" summary="nonexistent power save mode"/>
 | 
			
		||||
      <entry name="invalid_mode" value="1" summary="inexistent power save mode"/>
 | 
			
		||||
    </enum>
 | 
			
		||||
 | 
			
		||||
    <request name="set_mode">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,7 +88,7 @@
 | 
			
		|||
      supported buffer type. The "buffer_done" event is sent afterwards to
 | 
			
		||||
      indicate that all supported buffer types have been enumerated. The client
 | 
			
		||||
      will then be able to send a "copy" request. If the capture is successful,
 | 
			
		||||
      the compositor will send a "flags" event followed by a "ready" event.
 | 
			
		||||
      the compositor will send a "flags" followed by a "ready" event.
 | 
			
		||||
 | 
			
		||||
      For objects version 2 or lower, wl_shm buffers are always supported, ie.
 | 
			
		||||
      the "buffer" event is guaranteed to be sent.
 | 
			
		||||
| 
						 | 
				
			
			@ -114,12 +114,12 @@
 | 
			
		|||
 | 
			
		||||
    <request name="copy">
 | 
			
		||||
      <description summary="copy the frame">
 | 
			
		||||
        Copy the frame to the supplied buffer. The buffer must have the
 | 
			
		||||
        Copy the frame to the supplied buffer. The buffer must have a the
 | 
			
		||||
        correct size, see zwlr_screencopy_frame_v1.buffer and
 | 
			
		||||
        zwlr_screencopy_frame_v1.linux_dmabuf. The buffer needs to have a
 | 
			
		||||
        supported format.
 | 
			
		||||
 | 
			
		||||
        If the frame is successfully copied, "flags" and "ready" events are
 | 
			
		||||
        If the frame is successfully copied, a "flags" and a "ready" events are
 | 
			
		||||
        sent. Otherwise, a "failed" event is sent.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="buffer" type="object" interface="wl_buffer"/>
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +147,8 @@
 | 
			
		|||
    <event name="ready">
 | 
			
		||||
      <description summary="indicates frame is available for reading">
 | 
			
		||||
        Called as soon as the frame is copied, indicating it is available
 | 
			
		||||
        for reading. This event includes the time at which the presentation took place.
 | 
			
		||||
        for reading. This event includes the time at which presentation happened
 | 
			
		||||
        at.
 | 
			
		||||
 | 
			
		||||
        The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples,
 | 
			
		||||
        each component being an unsigned 32-bit value. Whole seconds are in
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										32
									
								
								release.sh
									
										
									
									
									
								
							
							
						
						
									
										32
									
								
								release.sh
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,32 +0,0 @@
 | 
			
		|||
#!/bin/sh -eu
 | 
			
		||||
 | 
			
		||||
prev=$(git describe --tags --abbrev=0)
 | 
			
		||||
next=$(meson rewrite kwargs info project / | jq -r '.kwargs["project#/"].version')
 | 
			
		||||
 | 
			
		||||
case "$next" in
 | 
			
		||||
*-dev)
 | 
			
		||||
	echo "This is a development version"
 | 
			
		||||
	exit 1
 | 
			
		||||
	;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
if [ "$prev" = "$next" ]; then
 | 
			
		||||
	echo "Version not bumped in meson.build"
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if ! git diff-index --quiet HEAD -- meson.build; then
 | 
			
		||||
	echo "meson.build not committed"
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
shortlog="$(git shortlog --no-merges "$prev..")"
 | 
			
		||||
(echo "wlroots $next"; echo ""; echo "$shortlog") | git tag "$next" -ase -F -
 | 
			
		||||
 | 
			
		||||
prefix=wlroots-$next
 | 
			
		||||
archive=$prefix.tar.gz
 | 
			
		||||
git archive --prefix="$prefix/" -o "$archive" "$next"
 | 
			
		||||
gpg --output "$archive".sig --detach-sig "$archive"
 | 
			
		||||
 | 
			
		||||
git push --follow-tags
 | 
			
		||||
glab release create "$next" "$archive" "$archive.sig" --notes ""
 | 
			
		||||
| 
						 | 
				
			
			@ -9,6 +9,7 @@
 | 
			
		|||
#include <wlr/util/log.h>
 | 
			
		||||
#include <xf86drm.h>
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "render/allocator/gbm.h"
 | 
			
		||||
#include "render/drm_format_set.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -38,12 +39,40 @@ static bool export_gbm_bo(struct gbm_bo *bo,
 | 
			
		|||
	attribs.modifier = gbm_bo_get_modifier(bo);
 | 
			
		||||
 | 
			
		||||
	int i;
 | 
			
		||||
	int32_t handle = -1;
 | 
			
		||||
	for (i = 0; i < attribs.n_planes; ++i) {
 | 
			
		||||
#if HAVE_GBM_BO_GET_FD_FOR_PLANE
 | 
			
		||||
		(void)handle;
 | 
			
		||||
 | 
			
		||||
		attribs.fd[i] = gbm_bo_get_fd_for_plane(bo, i);
 | 
			
		||||
		if (attribs.fd[i] < 0) {
 | 
			
		||||
			wlr_log(WLR_ERROR, "gbm_bo_get_fd_for_plane failed");
 | 
			
		||||
			goto error_fd;
 | 
			
		||||
		}
 | 
			
		||||
#else
 | 
			
		||||
		// GBM is lacking a function to get a FD for a given plane. Instead,
 | 
			
		||||
		// check all planes have the same handle. We can't use
 | 
			
		||||
		// drmPrimeHandleToFD because that messes up handle ref'counting in
 | 
			
		||||
		// the user-space driver.
 | 
			
		||||
		union gbm_bo_handle plane_handle = gbm_bo_get_handle_for_plane(bo, i);
 | 
			
		||||
		if (plane_handle.s32 < 0) {
 | 
			
		||||
			wlr_log(WLR_ERROR, "gbm_bo_get_handle_for_plane failed");
 | 
			
		||||
			goto error_fd;
 | 
			
		||||
		}
 | 
			
		||||
		if (i == 0) {
 | 
			
		||||
			handle = plane_handle.s32;
 | 
			
		||||
		} else if (plane_handle.s32 != handle) {
 | 
			
		||||
			wlr_log(WLR_ERROR, "Failed to export GBM BO: "
 | 
			
		||||
				"all planes don't have the same GEM handle");
 | 
			
		||||
			goto error_fd;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		attribs.fd[i] = gbm_bo_get_fd(bo);
 | 
			
		||||
		if (attribs.fd[i] < 0) {
 | 
			
		||||
			wlr_log(WLR_ERROR, "gbm_bo_get_fd failed");
 | 
			
		||||
			goto error_fd;
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		attribs.offset[i] = gbm_bo_get_offset(bo, i);
 | 
			
		||||
		attribs.stride[i] = gbm_bo_get_stride_for_plane(bo, i);
 | 
			
		||||
| 
						 | 
				
			
			@ -97,6 +126,7 @@ static struct wlr_gbm_buffer *create_buffer(struct wlr_gbm_allocator *alloc,
 | 
			
		|||
	}
 | 
			
		||||
	wlr_buffer_init(&buffer->base, &buffer_impl, width, height);
 | 
			
		||||
	buffer->gbm_bo = bo;
 | 
			
		||||
	wl_list_insert(&alloc->buffers, &buffer->link);
 | 
			
		||||
 | 
			
		||||
	if (!export_gbm_bo(bo, &buffer->dmabuf)) {
 | 
			
		||||
		free(buffer);
 | 
			
		||||
| 
						 | 
				
			
			@ -111,8 +141,6 @@ static struct wlr_gbm_buffer *create_buffer(struct wlr_gbm_allocator *alloc,
 | 
			
		|||
		buffer->dmabuf.modifier = fallback_modifier;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_list_insert(&alloc->buffers, &buffer->link);
 | 
			
		||||
 | 
			
		||||
	char *format_name = drmGetFormatName(buffer->dmabuf.format);
 | 
			
		||||
	char *modifier_name = drmGetFormatModifierName(buffer->dmabuf.modifier);
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Allocated %dx%d GBM buffer "
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,12 +13,15 @@ wlr_files += files(
 | 
			
		|||
 | 
			
		||||
gbm = disabler()
 | 
			
		||||
if 'gbm' in allocators or 'auto' in allocators
 | 
			
		||||
	gbm = dependency('gbm', version: '>=21.1', required: 'gbm' in allocators)
 | 
			
		||||
	gbm = dependency('gbm', version: '>=17.1.0', required: 'gbm' in allocators)
 | 
			
		||||
endif
 | 
			
		||||
if gbm.found()
 | 
			
		||||
	wlr_files += files('gbm.c')
 | 
			
		||||
	wlr_deps += gbm
 | 
			
		||||
	features += { 'gbm-allocator': true }
 | 
			
		||||
 | 
			
		||||
	has = cc.has_function('gbm_bo_get_fd_for_plane', dependencies: [gbm])
 | 
			
		||||
	internal_config.set10('HAVE_GBM_BO_GET_FD_FOR_PLANE', has)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
udmabuf = false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										219
									
								
								render/color.c
									
										
									
									
									
								
							
							
						
						
									
										219
									
								
								render/color.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -21,92 +21,25 @@ static const struct wlr_color_primaries COLOR_PRIMARIES_BT2020 = { // code point
 | 
			
		|||
	.white = { 0.3127, 0.3290 },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void wlr_color_transform_init(struct wlr_color_transform *tr, enum wlr_color_transform_type type) {
 | 
			
		||||
	*tr = (struct wlr_color_transform){
 | 
			
		||||
		.type = type,
 | 
			
		||||
		.ref_count = 1,
 | 
			
		||||
	};
 | 
			
		||||
	wlr_addon_set_init(&tr->addons);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct wlr_color_transform *wlr_color_transform_init_linear_to_inverse_eotf(
 | 
			
		||||
		enum wlr_color_transfer_function tf) {
 | 
			
		||||
	struct wlr_color_transform_inverse_eotf *tx = calloc(1, sizeof(*tx));
 | 
			
		||||
struct wlr_color_transform *wlr_color_transform_init_srgb(void) {
 | 
			
		||||
	struct wlr_color_transform *tx = calloc(1, sizeof(struct wlr_color_transform));
 | 
			
		||||
	if (!tx) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	wlr_color_transform_init(&tx->base, COLOR_TRANSFORM_INVERSE_EOTF);
 | 
			
		||||
	tx->tf = tf;
 | 
			
		||||
	return &tx->base;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
	uint16_t *lut_3x1d = malloc(3 * dim * sizeof(lut_3x1d[0]));
 | 
			
		||||
	if (lut_3x1d == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memcpy(&lut_3x1d[0 * dim], r, dim * sizeof(lut_3x1d[0]));
 | 
			
		||||
	memcpy(&lut_3x1d[1 * dim], g, dim * sizeof(lut_3x1d[0]));
 | 
			
		||||
	memcpy(&lut_3x1d[2 * dim], b, dim * sizeof(lut_3x1d[0]));
 | 
			
		||||
 | 
			
		||||
	struct wlr_color_transform_lut_3x1d *tx = calloc(1, sizeof(*tx));
 | 
			
		||||
	if (!tx) {
 | 
			
		||||
		free(lut_3x1d);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	wlr_color_transform_init(&tx->base, COLOR_TRANSFORM_LUT_3X1D);
 | 
			
		||||
	tx->lut_3x1d = lut_3x1d;
 | 
			
		||||
	tx->dim = dim;
 | 
			
		||||
	return &tx->base;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct wlr_color_transform *wlr_color_transform_init_pipeline(
 | 
			
		||||
		struct wlr_color_transform **transforms, size_t len) {
 | 
			
		||||
	assert(len > 0);
 | 
			
		||||
 | 
			
		||||
	struct wlr_color_transform **copy = calloc(len, sizeof(copy[0]));
 | 
			
		||||
	if (copy == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_color_transform_pipeline *tx = calloc(1, sizeof(*tx));
 | 
			
		||||
	if (!tx) {
 | 
			
		||||
		free(copy);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	wlr_color_transform_init(&tx->base, COLOR_TRANSFORM_PIPELINE);
 | 
			
		||||
 | 
			
		||||
	// TODO: flatten nested pipeline transforms
 | 
			
		||||
	for (size_t i = 0; i < len; i++) {
 | 
			
		||||
		copy[i] = wlr_color_transform_ref(transforms[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tx->transforms = copy;
 | 
			
		||||
	tx->len = len;
 | 
			
		||||
 | 
			
		||||
	return &tx->base;
 | 
			
		||||
	tx->type = COLOR_TRANSFORM_SRGB;
 | 
			
		||||
	tx->ref_count = 1;
 | 
			
		||||
	wlr_addon_set_init(&tx->addons);
 | 
			
		||||
	return tx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void color_transform_destroy(struct wlr_color_transform *tr) {
 | 
			
		||||
	switch (tr->type) {
 | 
			
		||||
	case COLOR_TRANSFORM_INVERSE_EOTF:
 | 
			
		||||
	case COLOR_TRANSFORM_SRGB:
 | 
			
		||||
		break;
 | 
			
		||||
	case COLOR_TRANSFORM_LCMS2:
 | 
			
		||||
		color_transform_lcms2_finish(color_transform_lcms2_from_base(tr));
 | 
			
		||||
		break;
 | 
			
		||||
	case COLOR_TRANSFORM_LUT_3X1D:;
 | 
			
		||||
		struct wlr_color_transform_lut_3x1d *lut_3x1d = color_transform_lut_3x1d_from_base(tr);
 | 
			
		||||
		free(lut_3x1d->lut_3x1d);
 | 
			
		||||
		break;
 | 
			
		||||
	case COLOR_TRANSFORM_PIPELINE:;
 | 
			
		||||
		struct wlr_color_transform_pipeline *pipeline =
 | 
			
		||||
			wl_container_of(tr, pipeline, base);
 | 
			
		||||
		for (size_t i = 0; i < pipeline->len; i++) {
 | 
			
		||||
			wlr_color_transform_unref(pipeline->transforms[i]);
 | 
			
		||||
		}
 | 
			
		||||
		free(pipeline->transforms);
 | 
			
		||||
	case COLOR_TRANSFORM_LUT_3D:;
 | 
			
		||||
		struct wlr_color_transform_lut3d *lut3d =
 | 
			
		||||
			wlr_color_transform_lut3d_from_base(tr);
 | 
			
		||||
		free(lut3d->lut_3d);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	wlr_addon_set_finish(&tr->addons);
 | 
			
		||||
| 
						 | 
				
			
			@ -129,126 +62,11 @@ void wlr_color_transform_unref(struct wlr_color_transform *tr) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct wlr_color_transform_inverse_eotf *wlr_color_transform_inverse_eotf_from_base(
 | 
			
		||||
struct wlr_color_transform_lut3d *wlr_color_transform_lut3d_from_base(
 | 
			
		||||
		struct wlr_color_transform *tr) {
 | 
			
		||||
	assert(tr->type == COLOR_TRANSFORM_INVERSE_EOTF);
 | 
			
		||||
	struct wlr_color_transform_inverse_eotf *inverse_eotf = wl_container_of(tr, inverse_eotf, base);
 | 
			
		||||
	return inverse_eotf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
 | 
			
		||||
		struct wlr_color_transform *tr) {
 | 
			
		||||
	assert(tr->type == COLOR_TRANSFORM_LUT_3X1D);
 | 
			
		||||
	struct wlr_color_transform_lut_3x1d *lut_3x1d = wl_container_of(tr, lut_3x1d, base);
 | 
			
		||||
	return lut_3x1d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static float srgb_eval_inverse_eotf(float x) {
 | 
			
		||||
	// See https://www.w3.org/Graphics/Color/srgb
 | 
			
		||||
	if (x <= 0.0031308) {
 | 
			
		||||
		return 12.92 * x;
 | 
			
		||||
	} else {
 | 
			
		||||
		return 1.055 * powf(x, 1.0 / 2.4) - 0.055;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static float st2084_pq_eval_inverse_eotf(float x) {
 | 
			
		||||
	// H.273 TransferCharacteristics code point 16
 | 
			
		||||
	float c1 = 0.8359375;
 | 
			
		||||
	float c2 = 18.8515625;
 | 
			
		||||
	float c3 = 18.6875;
 | 
			
		||||
	float m = 78.84375;
 | 
			
		||||
	float n = 0.1593017578125;
 | 
			
		||||
	if (x < 0) {
 | 
			
		||||
		x = 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (x > 1) {
 | 
			
		||||
		x = 1;
 | 
			
		||||
	}
 | 
			
		||||
	float pow_n = powf(x, n);
 | 
			
		||||
	return powf((c1 + c2 * pow_n) / (1 + c3 * pow_n), m);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static float bt1886_eval_inverse_eotf(float x) {
 | 
			
		||||
	float lb = powf(0.0001, 1.0 / 2.4);
 | 
			
		||||
	float lw = powf(1.0, 1.0 / 2.4);
 | 
			
		||||
	float a  = powf(lw - lb, 2.4);
 | 
			
		||||
	float b  = lb / (lw - lb);
 | 
			
		||||
	return powf(x / a, 1.0 / 2.4) - b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static float transfer_function_eval_inverse_eotf(
 | 
			
		||||
		enum wlr_color_transfer_function tf, float x) {
 | 
			
		||||
	switch (tf) {
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
 | 
			
		||||
		return srgb_eval_inverse_eotf(x);
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
 | 
			
		||||
		return st2084_pq_eval_inverse_eotf(x);
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
 | 
			
		||||
		return x;
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
 | 
			
		||||
		return powf(x, 1.0 / 2.2);
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
 | 
			
		||||
		return bt1886_eval_inverse_eotf(x);
 | 
			
		||||
	}
 | 
			
		||||
	abort(); // unreachable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void color_transform_inverse_eotf_eval(
 | 
			
		||||
		struct wlr_color_transform_inverse_eotf *tr,
 | 
			
		||||
		float out[static 3], const float in[static 3]) {
 | 
			
		||||
	for (size_t i = 0; i < 3; i++) {
 | 
			
		||||
		out[i] = transfer_function_eval_inverse_eotf(tr->tf, in[i]);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static float lut_1d_get(const uint16_t *lut, size_t len, size_t i) {
 | 
			
		||||
	if (i >= len) {
 | 
			
		||||
		i = len - 1;
 | 
			
		||||
	}
 | 
			
		||||
	return (float) lut[i] / UINT16_MAX;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static float lut_1d_eval(const uint16_t *lut, size_t len, float x) {
 | 
			
		||||
	double pos = x * (len - 1);
 | 
			
		||||
	double int_part;
 | 
			
		||||
	double frac_part = modf(pos, &int_part);
 | 
			
		||||
	size_t i = (size_t) int_part;
 | 
			
		||||
	double a = lut_1d_get(lut, len, i);
 | 
			
		||||
	double b = lut_1d_get(lut, len, i + 1);
 | 
			
		||||
	return a * (1 - frac_part) + b * frac_part;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void color_transform_lut_3x1d_eval(struct wlr_color_transform_lut_3x1d *tr,
 | 
			
		||||
		float out[static 3], const float in[static 3]) {
 | 
			
		||||
	for (size_t i = 0; i < 3; i++) {
 | 
			
		||||
		out[i] = lut_1d_eval(&tr->lut_3x1d[tr->dim * i], tr->dim, in[i]);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wlr_color_transform_eval(struct wlr_color_transform *tr,
 | 
			
		||||
		float out[static 3], const float in[static 3]) {
 | 
			
		||||
	switch (tr->type) {
 | 
			
		||||
	case COLOR_TRANSFORM_INVERSE_EOTF:
 | 
			
		||||
		color_transform_inverse_eotf_eval(wlr_color_transform_inverse_eotf_from_base(tr), out, in);
 | 
			
		||||
		break;
 | 
			
		||||
	case COLOR_TRANSFORM_LCMS2:
 | 
			
		||||
		color_transform_lcms2_eval(color_transform_lcms2_from_base(tr), out, in);
 | 
			
		||||
		break;
 | 
			
		||||
	case COLOR_TRANSFORM_LUT_3X1D:
 | 
			
		||||
		color_transform_lut_3x1d_eval(color_transform_lut_3x1d_from_base(tr), out, in);
 | 
			
		||||
		break;
 | 
			
		||||
	case COLOR_TRANSFORM_PIPELINE:;
 | 
			
		||||
		struct wlr_color_transform_pipeline *pipeline =
 | 
			
		||||
			wl_container_of(tr, pipeline, base);
 | 
			
		||||
		float color[3];
 | 
			
		||||
		memcpy(color, in, sizeof(color));
 | 
			
		||||
		for (size_t i = 0; i < pipeline->len; i++) {
 | 
			
		||||
			wlr_color_transform_eval(pipeline->transforms[i], color, color);
 | 
			
		||||
		}
 | 
			
		||||
		memcpy(out, color, sizeof(color));
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	assert(tr->type == COLOR_TRANSFORM_LUT_3D);
 | 
			
		||||
	struct wlr_color_transform_lut3d *lut3d = wl_container_of(tr, lut3d, base);
 | 
			
		||||
	return lut3d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wlr_color_primaries_from_named(struct wlr_color_primaries *out,
 | 
			
		||||
| 
						 | 
				
			
			@ -321,13 +139,6 @@ void wlr_color_transfer_function_get_default_luminance(enum wlr_color_transfer_f
 | 
			
		|||
			.reference = 203,
 | 
			
		||||
		};
 | 
			
		||||
		break;
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
 | 
			
		||||
		*lum = (struct wlr_color_luminances){
 | 
			
		||||
			.min = 0.01,
 | 
			
		||||
			.max = 100,
 | 
			
		||||
			.reference = 100,
 | 
			
		||||
		};
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		*lum = (struct wlr_color_luminances){
 | 
			
		||||
			.min = 0.2,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,5 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <wlr/render/color.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
#include "render/color.h"
 | 
			
		||||
 | 
			
		||||
struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
 | 
			
		||||
		const void *data, size_t size) {
 | 
			
		||||
| 
						 | 
				
			
			@ -8,17 +7,3 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
 | 
			
		|||
		"LCMS2 is compile-time disabled");
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct wlr_color_transform_lcms2 *color_transform_lcms2_from_base(
 | 
			
		||||
		struct wlr_color_transform *tr) {
 | 
			
		||||
	abort(); // unreachable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void color_transform_lcms2_finish(struct wlr_color_transform_lcms2 *tr) {
 | 
			
		||||
	abort(); // unreachable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void color_transform_lcms2_eval(struct wlr_color_transform_lcms2 *tr,
 | 
			
		||||
		float out[static 3], const float in[static 3]) {
 | 
			
		||||
	abort(); // unreachable
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,17 +1,9 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <lcms2.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
#include <wlr/render/color.h>
 | 
			
		||||
#include "render/color.h"
 | 
			
		||||
 | 
			
		||||
struct wlr_color_transform_lcms2 {
 | 
			
		||||
	struct wlr_color_transform base;
 | 
			
		||||
 | 
			
		||||
	cmsContext ctx;
 | 
			
		||||
	cmsHTRANSFORM lcms;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const cmsCIExyY srgb_whitepoint = { 0.3127, 0.3291, 1 };
 | 
			
		||||
 | 
			
		||||
static const cmsCIExyYTRIPLE srgb_primaries = {
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +18,7 @@ static void handle_lcms_error(cmsContext ctx, cmsUInt32Number code, const char *
 | 
			
		|||
 | 
			
		||||
struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
 | 
			
		||||
		const void *data, size_t size) {
 | 
			
		||||
	struct wlr_color_transform_lcms2 *tx = NULL;
 | 
			
		||||
	struct wlr_color_transform_lut3d *tx = NULL;
 | 
			
		||||
 | 
			
		||||
	cmsContext ctx = cmsCreateContext(NULL, NULL);
 | 
			
		||||
	if (ctx == NULL) {
 | 
			
		||||
| 
						 | 
				
			
			@ -39,18 +31,18 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
 | 
			
		|||
	cmsHPROFILE icc_profile = cmsOpenProfileFromMemTHR(ctx, data, size);
 | 
			
		||||
	if (icc_profile == NULL) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "cmsOpenProfileFromMemTHR failed");
 | 
			
		||||
		goto error_ctx;
 | 
			
		||||
		goto out_ctx;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cmsGetDeviceClass(icc_profile) != cmsSigDisplayClass) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "ICC profile must have the Display device class");
 | 
			
		||||
		goto error_icc_profile;
 | 
			
		||||
		goto out_icc_profile;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmsToneCurve *linear_tone_curve = cmsBuildGamma(ctx, 1);
 | 
			
		||||
	if (linear_tone_curve == NULL) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "cmsBuildGamma failed");
 | 
			
		||||
		goto error_icc_profile;
 | 
			
		||||
		goto out_icc_profile;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmsToneCurve *linear_tf[] = {
 | 
			
		||||
| 
						 | 
				
			
			@ -60,54 +52,68 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_icc(
 | 
			
		|||
	};
 | 
			
		||||
	cmsHPROFILE srgb_profile = cmsCreateRGBProfileTHR(ctx, &srgb_whitepoint,
 | 
			
		||||
		&srgb_primaries, linear_tf);
 | 
			
		||||
	cmsFreeToneCurve(linear_tone_curve);
 | 
			
		||||
	if (srgb_profile == NULL) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "cmsCreateRGBProfileTHR failed");
 | 
			
		||||
		goto error_icc_profile;
 | 
			
		||||
		goto out_linear_tone_curve;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmsHTRANSFORM lcms_tr = cmsCreateTransformTHR(ctx,
 | 
			
		||||
		srgb_profile, TYPE_RGB_FLT, icc_profile, TYPE_RGB_FLT,
 | 
			
		||||
		INTENT_RELATIVE_COLORIMETRIC, 0);
 | 
			
		||||
	cmsCloseProfile(srgb_profile);
 | 
			
		||||
	cmsCloseProfile(icc_profile);
 | 
			
		||||
	if (lcms_tr == NULL) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "cmsCreateTransformTHR failed");
 | 
			
		||||
		goto error_ctx;
 | 
			
		||||
		goto out_srgb_profile;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tx = calloc(1, sizeof(*tx));
 | 
			
		||||
	size_t dim_len = 33;
 | 
			
		||||
	float *lut_3d = calloc(3 * dim_len * dim_len * dim_len, sizeof(float));
 | 
			
		||||
	if (lut_3d == NULL) {
 | 
			
		||||
		wlr_log_errno(WLR_ERROR, "Allocation failed");
 | 
			
		||||
		goto out_lcms_tr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	float factor = 1.0f / (dim_len - 1);
 | 
			
		||||
	for (size_t b_index = 0; b_index < dim_len; b_index++) {
 | 
			
		||||
		for (size_t g_index = 0; g_index < dim_len; g_index++) {
 | 
			
		||||
			for (size_t r_index = 0; r_index < dim_len; r_index++) {
 | 
			
		||||
				float rgb_in[3] = {
 | 
			
		||||
					r_index * factor,
 | 
			
		||||
					g_index * factor,
 | 
			
		||||
					b_index * factor,
 | 
			
		||||
				};
 | 
			
		||||
				float rgb_out[3];
 | 
			
		||||
				// TODO: use a single call to cmsDoTransform for the entire calculation?
 | 
			
		||||
				// this does require allocating an extra temp buffer
 | 
			
		||||
				cmsDoTransform(lcms_tr, rgb_in, rgb_out, 1);
 | 
			
		||||
 | 
			
		||||
				size_t offset = 3 * (r_index + dim_len * g_index + dim_len * dim_len * b_index);
 | 
			
		||||
				// TODO: maybe clamp values to [0.0, 1.0] here?
 | 
			
		||||
				lut_3d[offset] = rgb_out[0];
 | 
			
		||||
				lut_3d[offset + 1] = rgb_out[1];
 | 
			
		||||
				lut_3d[offset + 2] = rgb_out[2];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tx = calloc(1, sizeof(struct wlr_color_transform_lut3d));
 | 
			
		||||
	if (!tx) {
 | 
			
		||||
		cmsDeleteTransform(lcms_tr);
 | 
			
		||||
		goto error_ctx;
 | 
			
		||||
		goto out_lcms_tr;
 | 
			
		||||
	}
 | 
			
		||||
	wlr_color_transform_init(&tx->base, COLOR_TRANSFORM_LCMS2);
 | 
			
		||||
	tx->base.type = COLOR_TRANSFORM_LUT_3D;
 | 
			
		||||
	tx->dim_len = dim_len;
 | 
			
		||||
	tx->lut_3d = lut_3d;
 | 
			
		||||
	tx->base.ref_count = 1;
 | 
			
		||||
	wlr_addon_set_init(&tx->base.addons);
 | 
			
		||||
 | 
			
		||||
	tx->ctx = ctx;
 | 
			
		||||
	tx->lcms = lcms_tr;
 | 
			
		||||
 | 
			
		||||
	return &tx->base;
 | 
			
		||||
 | 
			
		||||
error_icc_profile:
 | 
			
		||||
out_lcms_tr:
 | 
			
		||||
	cmsDeleteTransform(lcms_tr);
 | 
			
		||||
out_linear_tone_curve:
 | 
			
		||||
	cmsFreeToneCurve(linear_tone_curve);
 | 
			
		||||
out_srgb_profile:
 | 
			
		||||
	cmsCloseProfile(srgb_profile);
 | 
			
		||||
out_icc_profile:
 | 
			
		||||
	cmsCloseProfile(icc_profile);
 | 
			
		||||
error_ctx:
 | 
			
		||||
out_ctx:
 | 
			
		||||
	cmsDeleteContext(ctx);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void color_transform_lcms2_finish(struct wlr_color_transform_lcms2 *tr) {
 | 
			
		||||
	cmsDeleteTransform(tr->lcms);
 | 
			
		||||
	cmsDeleteContext(tr->ctx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct wlr_color_transform_lcms2 *color_transform_lcms2_from_base(
 | 
			
		||||
		struct wlr_color_transform *tr) {
 | 
			
		||||
	assert(tr->type == COLOR_TRANSFORM_LCMS2);
 | 
			
		||||
	struct wlr_color_transform_lcms2 *lcms2 = wl_container_of(tr, lcms2, base);
 | 
			
		||||
	return lcms2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void color_transform_lcms2_eval(struct wlr_color_transform_lcms2 *tr,
 | 
			
		||||
		float out[static 3], const float in[static 3]) {
 | 
			
		||||
	cmsDoTransform(tr->lcms, in, out, 1);
 | 
			
		||||
	return &tx->base;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										20
									
								
								render/egl.c
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								render/egl.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -260,8 +260,7 @@ static struct wlr_egl *egl_create(void) {
 | 
			
		|||
	return egl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool egl_init_display(struct wlr_egl *egl, EGLDisplay display,
 | 
			
		||||
		bool allow_software) {
 | 
			
		||||
static bool egl_init_display(struct wlr_egl *egl, EGLDisplay display) {
 | 
			
		||||
	egl->display = display;
 | 
			
		||||
 | 
			
		||||
	EGLint major, minor;
 | 
			
		||||
| 
						 | 
				
			
			@ -327,8 +326,9 @@ static bool egl_init_display(struct wlr_egl *egl, EGLDisplay display,
 | 
			
		|||
 | 
			
		||||
		// The only way a non-DRM device is selected is when the user
 | 
			
		||||
		// explicitly picks software rendering
 | 
			
		||||
		if (check_egl_ext(device_exts_str, "EGL_MESA_device_software")) {
 | 
			
		||||
			if (allow_software || env_parse_bool("WLR_RENDERER_ALLOW_SOFTWARE")) {
 | 
			
		||||
		if (check_egl_ext(device_exts_str, "EGL_MESA_device_software") &&
 | 
			
		||||
				egl->exts.EXT_device_drm) {
 | 
			
		||||
			if (env_parse_bool("WLR_RENDERER_ALLOW_SOFTWARE")) {
 | 
			
		||||
				wlr_log(WLR_INFO, "Using software rendering");
 | 
			
		||||
			} else {
 | 
			
		||||
				wlr_log(WLR_ERROR, "Software rendering detected, please use "
 | 
			
		||||
| 
						 | 
				
			
			@ -382,7 +382,7 @@ static bool egl_init_display(struct wlr_egl *egl, EGLDisplay display,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static bool egl_init(struct wlr_egl *egl, EGLenum platform,
 | 
			
		||||
		void *remote_display, bool allow_software) {
 | 
			
		||||
		void *remote_display) {
 | 
			
		||||
	EGLint display_attribs[3] = {0};
 | 
			
		||||
	size_t display_attribs_len = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -401,7 +401,7 @@ static bool egl_init(struct wlr_egl *egl, EGLenum platform,
 | 
			
		|||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!egl_init_display(egl, display, allow_software)) {
 | 
			
		||||
	if (!egl_init_display(egl, display)) {
 | 
			
		||||
		if (egl->exts.KHR_display_reference) {
 | 
			
		||||
			eglTerminate(display);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -556,8 +556,6 @@ static int open_render_node(int drm_fd) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
 | 
			
		||||
	bool allow_software = drm_fd < 0;
 | 
			
		||||
 | 
			
		||||
	struct wlr_egl *egl = egl_create();
 | 
			
		||||
	if (egl == NULL) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "Failed to create EGL context");
 | 
			
		||||
| 
						 | 
				
			
			@ -571,7 +569,7 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
 | 
			
		|||
		 */
 | 
			
		||||
		EGLDeviceEXT egl_device = get_egl_device_from_drm_fd(egl, drm_fd);
 | 
			
		||||
		if (egl_device != EGL_NO_DEVICE_EXT) {
 | 
			
		||||
			if (egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device, allow_software)) {
 | 
			
		||||
			if (egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device)) {
 | 
			
		||||
				wlr_log(WLR_DEBUG, "Using EGL_PLATFORM_DEVICE_EXT");
 | 
			
		||||
				return egl;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -596,7 +594,7 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
 | 
			
		|||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (egl_init(egl, EGL_PLATFORM_GBM_KHR, egl->gbm_device, allow_software)) {
 | 
			
		||||
		if (egl_init(egl, EGL_PLATFORM_GBM_KHR, egl->gbm_device)) {
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Using EGL_PLATFORM_GBM_KHR");
 | 
			
		||||
			return egl;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -635,7 +633,7 @@ struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display,
 | 
			
		|||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!egl_init_display(egl, display, true)) {
 | 
			
		||||
	if (!egl_init_display(egl, display)) {
 | 
			
		||||
		free(egl);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,8 +21,8 @@ void wlr_render_pass_add_texture(struct wlr_render_pass *render_pass,
 | 
			
		|||
	if (!wlr_fbox_empty(&options->src_box)) {
 | 
			
		||||
		const struct wlr_fbox *box = &options->src_box;
 | 
			
		||||
		assert(box->x >= 0 && box->y >= 0 &&
 | 
			
		||||
		(uint32_t)(box->x + box->width) <= options->texture->width &&
 | 
			
		||||
		(uint32_t)(box->y + box->height) <= options->texture->height);
 | 
			
		||||
			box->x + box->width <= options->texture->width &&
 | 
			
		||||
			box->y + box->height <= options->texture->height);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	render_pass->impl->add_texture(render_pass, options);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,8 +18,6 @@ static void swapchain_handle_allocator_destroy(struct wl_listener *listener,
 | 
			
		|||
struct wlr_swapchain *wlr_swapchain_create(
 | 
			
		||||
		struct wlr_allocator *alloc, int width, int height,
 | 
			
		||||
		const struct wlr_drm_format *format) {
 | 
			
		||||
	assert(width > 0 && height > 0);
 | 
			
		||||
 | 
			
		||||
	struct wlr_swapchain *swapchain = calloc(1, sizeof(*swapchain));
 | 
			
		||||
	if (swapchain == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,33 +57,28 @@ static void convert_pixman_box_to_vk_rect(const pixman_box32_t *box, VkRect2D *r
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static float color_to_linear(float non_linear) {
 | 
			
		||||
	return pow(non_linear, 2.2);
 | 
			
		||||
	// See https://www.w3.org/Graphics/Color/srgb
 | 
			
		||||
	return (non_linear > 0.04045) ?
 | 
			
		||||
		pow((non_linear + 0.055) / 1.055, 2.4) :
 | 
			
		||||
		non_linear / 12.92;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static float color_to_linear_premult(float non_linear, float alpha) {
 | 
			
		||||
	return (alpha == 0) ? 0 : color_to_linear(non_linear / alpha) * alpha;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void encode_proj_matrix(const float mat3[9], float mat4[4][4]) {
 | 
			
		||||
	float result[4][4] = {
 | 
			
		||||
		{ mat3[0], mat3[1], 0, mat3[2] },
 | 
			
		||||
		{ mat3[3], mat3[4], 0, mat3[5] },
 | 
			
		||||
		{ 0, 0, 1, 0 },
 | 
			
		||||
		{ 0, 0, 0, 1 },
 | 
			
		||||
	};
 | 
			
		||||
static void mat3_to_mat4(const float mat3[9], float mat4[4][4]) {
 | 
			
		||||
	memset(mat4, 0, sizeof(float) * 16);
 | 
			
		||||
	mat4[0][0] = mat3[0];
 | 
			
		||||
	mat4[0][1] = mat3[1];
 | 
			
		||||
	mat4[0][3] = mat3[2];
 | 
			
		||||
 | 
			
		||||
	memcpy(mat4, result, sizeof(result));
 | 
			
		||||
}
 | 
			
		||||
	mat4[1][0] = mat3[3];
 | 
			
		||||
	mat4[1][1] = mat3[4];
 | 
			
		||||
	mat4[1][3] = mat3[5];
 | 
			
		||||
 | 
			
		||||
static void encode_color_matrix(const float mat3[9], float mat4[4][4]) {
 | 
			
		||||
	float result[4][4] = {
 | 
			
		||||
		{ mat3[0], mat3[1], mat3[2], 0 },
 | 
			
		||||
		{ mat3[3], mat3[4], mat3[5], 0 },
 | 
			
		||||
		{ mat3[6], mat3[7], mat3[8], 0 },
 | 
			
		||||
		{ 0, 0, 0, 0 },
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	memcpy(mat4, result, sizeof(result));
 | 
			
		||||
	mat4[2][2] = 1.f;
 | 
			
		||||
	mat4[3][3] = 1.f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void render_pass_destroy(struct wlr_vk_render_pass *pass) {
 | 
			
		||||
| 
						 | 
				
			
			@ -146,11 +141,6 @@ static VkSemaphore render_pass_wait_sync_file(struct wlr_vk_render_pass *pass,
 | 
			
		|||
	return *sem_ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static float get_luminance_multiplier(const struct wlr_color_luminances *src_lum,
 | 
			
		||||
		const struct wlr_color_luminances *dst_lum) {
 | 
			
		||||
	return (dst_lum->reference / src_lum->reference) * (src_lum->max / dst_lum->max);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
 | 
			
		||||
	struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass);
 | 
			
		||||
	struct wlr_vk_renderer *renderer = pass->renderer;
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +162,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
 | 
			
		|||
	assert(stage_cb != NULL);
 | 
			
		||||
	renderer->stage.cb = NULL;
 | 
			
		||||
 | 
			
		||||
	if (pass->two_pass) {
 | 
			
		||||
	if (!pass->srgb_pathway) {
 | 
			
		||||
		// Apply output shader to map blend image to actual output image
 | 
			
		||||
		vkCmdNextSubpass(render_cb->vk, VK_SUBPASS_CONTENTS_INLINE);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -188,76 +178,25 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
 | 
			
		|||
			.uv_off = { 0, 0 },
 | 
			
		||||
			.uv_size = { 1, 1 },
 | 
			
		||||
		};
 | 
			
		||||
		encode_proj_matrix(final_matrix, vert_pcr_data.mat4);
 | 
			
		||||
 | 
			
		||||
		struct wlr_vk_color_transform *transform = NULL;
 | 
			
		||||
		size_t dim = 1;
 | 
			
		||||
		if (pass->color_transform && pass->color_transform->type != COLOR_TRANSFORM_INVERSE_EOTF) {
 | 
			
		||||
			transform = get_color_transform(pass->color_transform, renderer);
 | 
			
		||||
			assert(transform);
 | 
			
		||||
			dim = transform->lut_3d.dim;
 | 
			
		||||
		if (pass->color_transform && pass->color_transform->type == COLOR_TRANSFORM_LUT_3D) {
 | 
			
		||||
			struct wlr_color_transform_lut3d *lut3d =
 | 
			
		||||
				wlr_color_transform_lut3d_from_base(pass->color_transform);
 | 
			
		||||
			dim = lut3d->dim_len;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		struct wlr_vk_frag_output_pcr_data frag_pcr_data = {
 | 
			
		||||
			.luminance_multiplier = 1,
 | 
			
		||||
			.lut_3d_offset = 0.5f / dim,
 | 
			
		||||
			.lut_3d_scale = (float)(dim - 1) / dim,
 | 
			
		||||
		};
 | 
			
		||||
		mat3_to_mat4(final_matrix, vert_pcr_data.mat4);
 | 
			
		||||
 | 
			
		||||
		float matrix[9];
 | 
			
		||||
		if (pass->has_primaries) {
 | 
			
		||||
			struct wlr_color_primaries srgb;
 | 
			
		||||
			wlr_color_primaries_from_named(&srgb, WLR_COLOR_NAMED_PRIMARIES_SRGB);
 | 
			
		||||
 | 
			
		||||
			float srgb_to_xyz[9];
 | 
			
		||||
			wlr_color_primaries_to_xyz(&srgb, srgb_to_xyz);
 | 
			
		||||
			float dst_primaries_to_xyz[9];
 | 
			
		||||
			wlr_color_primaries_to_xyz(&pass->primaries, dst_primaries_to_xyz);
 | 
			
		||||
			float xyz_to_dst_primaries[9];
 | 
			
		||||
			matrix_invert(xyz_to_dst_primaries, dst_primaries_to_xyz);
 | 
			
		||||
 | 
			
		||||
			wlr_matrix_multiply(matrix, xyz_to_dst_primaries, srgb_to_xyz);
 | 
			
		||||
		if (pass->color_transform) {
 | 
			
		||||
			bind_pipeline(pass, render_buffer->plain.render_setup->output_pipe_lut3d);
 | 
			
		||||
		} else {
 | 
			
		||||
			wlr_matrix_identity(matrix);
 | 
			
		||||
			bind_pipeline(pass, render_buffer->plain.render_setup->output_pipe_srgb);
 | 
			
		||||
		}
 | 
			
		||||
		encode_color_matrix(matrix, frag_pcr_data.matrix);
 | 
			
		||||
 | 
			
		||||
		VkPipeline pipeline = VK_NULL_HANDLE;
 | 
			
		||||
		if (pass->color_transform && pass->color_transform->type != COLOR_TRANSFORM_INVERSE_EOTF) {
 | 
			
		||||
			pipeline = render_buffer->two_pass.render_setup->output_pipe_lut3d;
 | 
			
		||||
		} else {
 | 
			
		||||
			enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
 | 
			
		||||
			if (pass->color_transform && pass->color_transform->type == COLOR_TRANSFORM_INVERSE_EOTF) {
 | 
			
		||||
				struct wlr_color_transform_inverse_eotf *inverse_eotf =
 | 
			
		||||
					wlr_color_transform_inverse_eotf_from_base(pass->color_transform);
 | 
			
		||||
				tf = inverse_eotf->tf;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			switch (tf) {
 | 
			
		||||
			case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
 | 
			
		||||
				pipeline = render_buffer->two_pass.render_setup->output_pipe_identity;
 | 
			
		||||
				break;
 | 
			
		||||
			case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
 | 
			
		||||
				pipeline = render_buffer->two_pass.render_setup->output_pipe_srgb;
 | 
			
		||||
				break;
 | 
			
		||||
			case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
 | 
			
		||||
				pipeline = render_buffer->two_pass.render_setup->output_pipe_pq;
 | 
			
		||||
				break;
 | 
			
		||||
			case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
 | 
			
		||||
				pipeline = render_buffer->two_pass.render_setup->output_pipe_gamma22;
 | 
			
		||||
				break;
 | 
			
		||||
			case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
 | 
			
		||||
				pipeline = render_buffer->two_pass.render_setup->output_pipe_bt1886;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			struct wlr_color_luminances srgb_lum, dst_lum;
 | 
			
		||||
			wlr_color_transfer_function_get_default_luminance(
 | 
			
		||||
				WLR_COLOR_TRANSFER_FUNCTION_SRGB, &srgb_lum);
 | 
			
		||||
			wlr_color_transfer_function_get_default_luminance(tf, &dst_lum);
 | 
			
		||||
			frag_pcr_data.luminance_multiplier = get_luminance_multiplier(&srgb_lum, &dst_lum);
 | 
			
		||||
		}
 | 
			
		||||
		bind_pipeline(pass, pipeline);
 | 
			
		||||
		vkCmdPushConstants(render_cb->vk, renderer->output_pipe_layout,
 | 
			
		||||
			VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data);
 | 
			
		||||
		vkCmdPushConstants(render_cb->vk, renderer->output_pipe_layout,
 | 
			
		||||
| 
						 | 
				
			
			@ -265,13 +204,16 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
 | 
			
		|||
			sizeof(frag_pcr_data), &frag_pcr_data);
 | 
			
		||||
 | 
			
		||||
		VkDescriptorSet lut_ds;
 | 
			
		||||
		if (transform != NULL) {
 | 
			
		||||
		if (pass->color_transform && pass->color_transform->type == COLOR_TRANSFORM_LUT_3D) {
 | 
			
		||||
			struct wlr_vk_color_transform *transform =
 | 
			
		||||
				get_color_transform(pass->color_transform, renderer);
 | 
			
		||||
			assert(transform);
 | 
			
		||||
			lut_ds = transform->lut_3d.ds;
 | 
			
		||||
		} else {
 | 
			
		||||
			lut_ds = renderer->output_ds_lut3d_dummy;
 | 
			
		||||
		}
 | 
			
		||||
		VkDescriptorSet ds[] = {
 | 
			
		||||
			render_buffer->two_pass.blend_descriptor_set, // set 0
 | 
			
		||||
			render_buffer->plain.blend_descriptor_set, // set 0
 | 
			
		||||
			lut_ds, // set 1
 | 
			
		||||
		};
 | 
			
		||||
		size_t ds_len = sizeof(ds) / sizeof(ds[0]);
 | 
			
		||||
| 
						 | 
				
			
			@ -401,26 +343,30 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) {
 | 
			
		|||
 | 
			
		||||
	// also add acquire/release barriers for the current render buffer
 | 
			
		||||
	VkImageLayout src_layout = VK_IMAGE_LAYOUT_GENERAL;
 | 
			
		||||
	if (!pass->render_buffer_out->transitioned) {
 | 
			
		||||
		src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
 | 
			
		||||
		pass->render_buffer_out->transitioned = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pass->two_pass) {
 | 
			
		||||
	if (pass->srgb_pathway) {
 | 
			
		||||
		if (!render_buffer->srgb.transitioned) {
 | 
			
		||||
			src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
 | 
			
		||||
			render_buffer->srgb.transitioned = true;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if (!render_buffer->plain.transitioned) {
 | 
			
		||||
			src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
 | 
			
		||||
			render_buffer->plain.transitioned = true;
 | 
			
		||||
		}
 | 
			
		||||
		// The render pass changes the blend image layout from
 | 
			
		||||
		// color attachment to read only, so on each frame, before
 | 
			
		||||
		// the render pass starts, we change it back
 | 
			
		||||
		VkImageLayout blend_src_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 | 
			
		||||
		if (!render_buffer->two_pass.blend_transitioned) {
 | 
			
		||||
		if (!render_buffer->plain.blend_transitioned) {
 | 
			
		||||
			blend_src_layout = VK_IMAGE_LAYOUT_UNDEFINED;
 | 
			
		||||
			render_buffer->two_pass.blend_transitioned = true;
 | 
			
		||||
			render_buffer->plain.blend_transitioned = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		VkImageMemoryBarrier blend_acq_barrier = {
 | 
			
		||||
			.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
 | 
			
		||||
			.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
 | 
			
		||||
			.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
 | 
			
		||||
			.image = render_buffer->two_pass.blend_image,
 | 
			
		||||
			.image = render_buffer->plain.blend_image,
 | 
			
		||||
			.oldLayout = blend_src_layout,
 | 
			
		||||
			.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
 | 
			
		||||
			.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
 | 
			
		||||
| 
						 | 
				
			
			@ -617,7 +563,7 @@ error:
 | 
			
		|||
 | 
			
		||||
static void render_pass_mark_box_updated(struct wlr_vk_render_pass *pass,
 | 
			
		||||
		const struct wlr_box *box) {
 | 
			
		||||
	if (!pass->two_pass) {
 | 
			
		||||
	if (pass->srgb_pathway) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -677,8 +623,11 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass,
 | 
			
		|||
		wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, proj);
 | 
			
		||||
		wlr_matrix_multiply(matrix, pass->projection, matrix);
 | 
			
		||||
 | 
			
		||||
		struct wlr_vk_render_format_setup *setup = pass->srgb_pathway ?
 | 
			
		||||
			pass->render_buffer->srgb.render_setup :
 | 
			
		||||
			pass->render_buffer->plain.render_setup;
 | 
			
		||||
		struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline(
 | 
			
		||||
			pass->render_setup,
 | 
			
		||||
			setup,
 | 
			
		||||
			&(struct wlr_vk_pipeline_key) {
 | 
			
		||||
				.source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR,
 | 
			
		||||
				.layout = { .ycbcr_format = NULL },
 | 
			
		||||
| 
						 | 
				
			
			@ -692,7 +641,7 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass,
 | 
			
		|||
			.uv_off = { 0, 0 },
 | 
			
		||||
			.uv_size = { 1, 1 },
 | 
			
		||||
		};
 | 
			
		||||
		encode_proj_matrix(matrix, vert_pcr_data.mat4);
 | 
			
		||||
		mat3_to_mat4(matrix, vert_pcr_data.mat4);
 | 
			
		||||
 | 
			
		||||
		bind_pipeline(pass, pipe->vk);
 | 
			
		||||
		vkCmdPushConstants(cb, pipe->layout->vk,
 | 
			
		||||
| 
						 | 
				
			
			@ -775,47 +724,20 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
 | 
			
		|||
			src_box.height / options->texture->height,
 | 
			
		||||
		},
 | 
			
		||||
	};
 | 
			
		||||
	encode_proj_matrix(matrix, vert_pcr_data.mat4);
 | 
			
		||||
 | 
			
		||||
	enum wlr_color_transfer_function tf = options->transfer_function;
 | 
			
		||||
	if (tf == 0) {
 | 
			
		||||
		tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool srgb_image_view = false;
 | 
			
		||||
	enum wlr_vk_texture_transform tex_transform = 0;
 | 
			
		||||
	switch (tf) {
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
 | 
			
		||||
		if (texture->using_mutable_srgb) {
 | 
			
		||||
			tex_transform = WLR_VK_TEXTURE_TRANSFORM_IDENTITY;
 | 
			
		||||
			srgb_image_view = true;
 | 
			
		||||
		} else {
 | 
			
		||||
			tex_transform = WLR_VK_TEXTURE_TRANSFORM_SRGB;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
 | 
			
		||||
		tex_transform = WLR_VK_TEXTURE_TRANSFORM_IDENTITY;
 | 
			
		||||
		break;
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
 | 
			
		||||
		tex_transform = WLR_VK_TEXTURE_TRANSFORM_ST2084_PQ;
 | 
			
		||||
		break;
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
 | 
			
		||||
		tex_transform = WLR_VK_TEXTURE_TRANSFORM_GAMMA22;
 | 
			
		||||
		break;
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
 | 
			
		||||
		tex_transform = WLR_VK_TEXTURE_TRANSFORM_BT1886;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	mat3_to_mat4(matrix, vert_pcr_data.mat4);
 | 
			
		||||
 | 
			
		||||
	struct wlr_vk_render_format_setup *setup = pass->srgb_pathway ?
 | 
			
		||||
		pass->render_buffer->srgb.render_setup :
 | 
			
		||||
		pass->render_buffer->plain.render_setup;
 | 
			
		||||
	struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline(
 | 
			
		||||
		pass->render_setup,
 | 
			
		||||
		setup,
 | 
			
		||||
		&(struct wlr_vk_pipeline_key) {
 | 
			
		||||
			.source = WLR_VK_SHADER_SOURCE_TEXTURE,
 | 
			
		||||
			.layout = {
 | 
			
		||||
				.ycbcr_format = texture->format->is_ycbcr ? texture->format : NULL,
 | 
			
		||||
				.filter_mode = options->filter_mode,
 | 
			
		||||
			},
 | 
			
		||||
			.texture_transform = tex_transform,
 | 
			
		||||
			.texture_transform = texture->transform,
 | 
			
		||||
			.blend_mode = !texture->has_alpha && alpha == 1.0 ?
 | 
			
		||||
				WLR_RENDER_BLEND_MODE_NONE : options->blend_mode,
 | 
			
		||||
		});
 | 
			
		||||
| 
						 | 
				
			
			@ -825,45 +747,12 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_vk_texture_view *view =
 | 
			
		||||
		vulkan_texture_get_or_create_view(texture, pipe->layout, srgb_image_view);
 | 
			
		||||
		vulkan_texture_get_or_create_view(texture, pipe->layout);
 | 
			
		||||
	if (!view) {
 | 
			
		||||
		pass->failed = true;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	float color_matrix[9];
 | 
			
		||||
	if (options->primaries != NULL) {
 | 
			
		||||
		struct wlr_color_primaries srgb;
 | 
			
		||||
		wlr_color_primaries_from_named(&srgb, WLR_COLOR_NAMED_PRIMARIES_SRGB);
 | 
			
		||||
 | 
			
		||||
		float src_primaries_to_xyz[9];
 | 
			
		||||
		wlr_color_primaries_to_xyz(options->primaries, src_primaries_to_xyz);
 | 
			
		||||
		float srgb_to_xyz[9];
 | 
			
		||||
		wlr_color_primaries_to_xyz(&srgb, srgb_to_xyz);
 | 
			
		||||
		float xyz_to_srgb[9];
 | 
			
		||||
		matrix_invert(xyz_to_srgb, srgb_to_xyz);
 | 
			
		||||
 | 
			
		||||
		wlr_matrix_multiply(color_matrix, xyz_to_srgb, src_primaries_to_xyz);
 | 
			
		||||
	} else {
 | 
			
		||||
		wlr_matrix_identity(color_matrix);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	float luminance_multiplier = 1;
 | 
			
		||||
	if (tf != WLR_COLOR_TRANSFER_FUNCTION_SRGB
 | 
			
		||||
			&& tf != WLR_COLOR_TRANSFER_FUNCTION_GAMMA22) {
 | 
			
		||||
		struct wlr_color_luminances src_lum, srgb_lum;
 | 
			
		||||
		wlr_color_transfer_function_get_default_luminance(tf, &src_lum);
 | 
			
		||||
		wlr_color_transfer_function_get_default_luminance(
 | 
			
		||||
			WLR_COLOR_TRANSFER_FUNCTION_SRGB, &srgb_lum);
 | 
			
		||||
		luminance_multiplier = get_luminance_multiplier(&src_lum, &srgb_lum);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_vk_frag_texture_pcr_data frag_pcr_data = {
 | 
			
		||||
		.alpha = alpha,
 | 
			
		||||
		.luminance_multiplier = luminance_multiplier,
 | 
			
		||||
	};
 | 
			
		||||
	encode_color_matrix(color_matrix, frag_pcr_data.matrix);
 | 
			
		||||
 | 
			
		||||
	bind_pipeline(pass, pipe->vk);
 | 
			
		||||
 | 
			
		||||
	vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS,
 | 
			
		||||
| 
						 | 
				
			
			@ -872,8 +761,8 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
 | 
			
		|||
	vkCmdPushConstants(cb, pipe->layout->vk,
 | 
			
		||||
		VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data);
 | 
			
		||||
	vkCmdPushConstants(cb, pipe->layout->vk,
 | 
			
		||||
		VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data),
 | 
			
		||||
		sizeof(frag_pcr_data), &frag_pcr_data);
 | 
			
		||||
		VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(float),
 | 
			
		||||
		&alpha);
 | 
			
		||||
 | 
			
		||||
	pixman_region32_t clip;
 | 
			
		||||
	get_clip_region(pass, options->clip, &clip);
 | 
			
		||||
| 
						 | 
				
			
			@ -951,9 +840,9 @@ void vk_color_transform_destroy(struct wlr_addon *addon) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
 | 
			
		||||
		struct wlr_color_transform *tr, size_t dim_len,
 | 
			
		||||
		const struct wlr_color_transform_lut3d *lut_3d,
 | 
			
		||||
		VkImage *image, VkImageView *image_view,
 | 
			
		||||
		VkDeviceMemory *memory, VkDescriptorSet *ds,
 | 
			
		||||
		VkDeviceMemory *memory,	VkDescriptorSet *ds,
 | 
			
		||||
		struct wlr_vk_descriptor_pool **ds_pool) {
 | 
			
		||||
	VkDevice dev = renderer->dev->dev;
 | 
			
		||||
	VkResult res;
 | 
			
		||||
| 
						 | 
				
			
			@ -977,7 +866,7 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
 | 
			
		|||
		.samples = VK_SAMPLE_COUNT_1_BIT,
 | 
			
		||||
		.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
 | 
			
		||||
		.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
 | 
			
		||||
		.extent = (VkExtent3D) { dim_len, dim_len, dim_len },
 | 
			
		||||
		.extent = (VkExtent3D) { lut_3d->dim_len, lut_3d->dim_len, lut_3d->dim_len },
 | 
			
		||||
		.tiling = VK_IMAGE_TILING_OPTIMAL,
 | 
			
		||||
		.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
 | 
			
		||||
	};
 | 
			
		||||
| 
						 | 
				
			
			@ -1038,7 +927,7 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	size_t bytes_per_block = 4 * sizeof(float);
 | 
			
		||||
	size_t size = dim_len * dim_len * dim_len * bytes_per_block;
 | 
			
		||||
	size_t size = lut_3d->dim_len * lut_3d->dim_len * lut_3d->dim_len * bytes_per_block;
 | 
			
		||||
	struct wlr_vk_buffer_span span = vulkan_get_stage_span(renderer,
 | 
			
		||||
		size, bytes_per_block);
 | 
			
		||||
	if (!span.buffer || span.alloc.size != size) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1046,26 +935,18 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
 | 
			
		|||
		goto fail_imageview;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	float sample_range = 1.0f / (dim_len - 1);
 | 
			
		||||
	char *map = (char *)span.buffer->cpu_mapping + span.alloc.start;
 | 
			
		||||
	float *dst = (float *)map;
 | 
			
		||||
	char *map = (char*)span.buffer->cpu_mapping + span.alloc.start;
 | 
			
		||||
	float *dst = (float*)map;
 | 
			
		||||
	size_t dim_len = lut_3d->dim_len;
 | 
			
		||||
	for (size_t b_index = 0; b_index < dim_len; b_index++) {
 | 
			
		||||
		for (size_t g_index = 0; g_index < dim_len; g_index++) {
 | 
			
		||||
			for (size_t r_index = 0; r_index < dim_len; r_index++) {
 | 
			
		||||
				size_t sample_index = r_index + dim_len * g_index + dim_len * dim_len * b_index;
 | 
			
		||||
				size_t src_offset = 3 * sample_index;
 | 
			
		||||
				size_t dst_offset = 4 * sample_index;
 | 
			
		||||
 | 
			
		||||
				float rgb_in[3] = {
 | 
			
		||||
					r_index * sample_range,
 | 
			
		||||
					g_index * sample_range,
 | 
			
		||||
					b_index * sample_range,
 | 
			
		||||
				};
 | 
			
		||||
				float rgb_out[3];
 | 
			
		||||
				wlr_color_transform_eval(tr, rgb_out, rgb_in);
 | 
			
		||||
 | 
			
		||||
				dst[dst_offset] = rgb_out[0];
 | 
			
		||||
				dst[dst_offset + 1] = rgb_out[1];
 | 
			
		||||
				dst[dst_offset + 2] = rgb_out[2];
 | 
			
		||||
				dst[dst_offset] = lut_3d->lut_3d[src_offset];
 | 
			
		||||
				dst[dst_offset + 1] = lut_3d->lut_3d[src_offset + 1];
 | 
			
		||||
				dst[dst_offset + 2] = lut_3d->lut_3d[src_offset + 2];
 | 
			
		||||
				dst[dst_offset + 3] = 1.0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -1078,9 +959,9 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
 | 
			
		|||
		VK_ACCESS_TRANSFER_WRITE_BIT);
 | 
			
		||||
	VkBufferImageCopy copy = {
 | 
			
		||||
		.bufferOffset = span.alloc.start,
 | 
			
		||||
		.imageExtent.width = dim_len,
 | 
			
		||||
		.imageExtent.height = dim_len,
 | 
			
		||||
		.imageExtent.depth = dim_len,
 | 
			
		||||
		.imageExtent.width = lut_3d->dim_len,
 | 
			
		||||
		.imageExtent.height = lut_3d->dim_len,
 | 
			
		||||
		.imageExtent.depth = lut_3d->dim_len,
 | 
			
		||||
		.imageSubresource.layerCount = 1,
 | 
			
		||||
		.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
 | 
			
		||||
	};
 | 
			
		||||
| 
						 | 
				
			
			@ -1131,10 +1012,9 @@ static struct wlr_vk_color_transform *vk_color_transform_create(
 | 
			
		|||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (transform->type != COLOR_TRANSFORM_INVERSE_EOTF) {
 | 
			
		||||
		vk_transform->lut_3d.dim = 33;
 | 
			
		||||
		if (!create_3d_lut_image(renderer, transform,
 | 
			
		||||
				vk_transform->lut_3d.dim,
 | 
			
		||||
	if (transform->type == COLOR_TRANSFORM_LUT_3D) {
 | 
			
		||||
		if (!create_3d_lut_image(renderer,
 | 
			
		||||
				wlr_color_transform_lut3d_from_base(transform),
 | 
			
		||||
				&vk_transform->lut_3d.image,
 | 
			
		||||
				&vk_transform->lut_3d.image_view,
 | 
			
		||||
				&vk_transform->lut_3d.memory,
 | 
			
		||||
| 
						 | 
				
			
			@ -1160,68 +1040,29 @@ static const struct wlr_addon_interface vk_color_transform_impl = {
 | 
			
		|||
 | 
			
		||||
struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *renderer,
 | 
			
		||||
		struct wlr_vk_render_buffer *buffer, const struct wlr_buffer_pass_options *options) {
 | 
			
		||||
	uint32_t inv_eotf;
 | 
			
		||||
	bool using_srgb_pathway;
 | 
			
		||||
	if (options != NULL && options->color_transform != NULL) {
 | 
			
		||||
		if (options->color_transform->type == COLOR_TRANSFORM_INVERSE_EOTF) {
 | 
			
		||||
			struct wlr_color_transform_inverse_eotf *tr =
 | 
			
		||||
				wlr_color_transform_inverse_eotf_from_base(options->color_transform);
 | 
			
		||||
			inv_eotf = tr->tf;
 | 
			
		||||
		} else {
 | 
			
		||||
			// Color transform is not an inverse EOTF
 | 
			
		||||
			inv_eotf = 0;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		// This is the default when unspecified
 | 
			
		||||
		inv_eotf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
 | 
			
		||||
	}
 | 
			
		||||
		using_srgb_pathway = false;
 | 
			
		||||
 | 
			
		||||
	bool using_linear_pathway = inv_eotf == WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
 | 
			
		||||
	bool using_srgb_pathway = inv_eotf == WLR_COLOR_TRANSFER_FUNCTION_SRGB &&
 | 
			
		||||
		buffer->srgb.out.framebuffer != VK_NULL_HANDLE;
 | 
			
		||||
	bool using_two_pass_pathway = !using_linear_pathway && !using_srgb_pathway;
 | 
			
		||||
 | 
			
		||||
	if (using_linear_pathway && !buffer->linear.out.image_view) {
 | 
			
		||||
		struct wlr_dmabuf_attributes attribs;
 | 
			
		||||
		wlr_buffer_get_dmabuf(buffer->wlr_buffer, &attribs);
 | 
			
		||||
		if (!vulkan_setup_one_pass_framebuffer(buffer, &attribs, false)) {
 | 
			
		||||
			wlr_log(WLR_ERROR, "Failed to set up blend image");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (using_two_pass_pathway) {
 | 
			
		||||
		if (options != NULL && options->color_transform != NULL &&
 | 
			
		||||
				!get_color_transform(options->color_transform, renderer)) {
 | 
			
		||||
		if (!get_color_transform(options->color_transform, renderer)) {
 | 
			
		||||
			/* Try to create a new color transform */
 | 
			
		||||
			if (!vk_color_transform_create(renderer, options->color_transform)) {
 | 
			
		||||
				wlr_log(WLR_ERROR, "Failed to create color transform");
 | 
			
		||||
				return NULL;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!buffer->two_pass.out.image_view) {
 | 
			
		||||
			struct wlr_dmabuf_attributes attribs;
 | 
			
		||||
			wlr_buffer_get_dmabuf(buffer->wlr_buffer, &attribs);
 | 
			
		||||
			if (!vulkan_setup_two_pass_framebuffer(buffer, &attribs)) {
 | 
			
		||||
				wlr_log(WLR_ERROR, "Failed to set up blend image");
 | 
			
		||||
				return NULL;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		// Use srgb pathway if it is the default/has already been set up
 | 
			
		||||
		using_srgb_pathway = buffer->srgb.framebuffer != VK_NULL_HANDLE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_vk_render_format_setup *render_setup;
 | 
			
		||||
	struct wlr_vk_render_buffer_out *buffer_out;
 | 
			
		||||
	if (using_two_pass_pathway) {
 | 
			
		||||
		render_setup = buffer->two_pass.render_setup;
 | 
			
		||||
		buffer_out = &buffer->two_pass.out;
 | 
			
		||||
	} else if (using_srgb_pathway) {
 | 
			
		||||
		render_setup = buffer->srgb.render_setup;
 | 
			
		||||
		buffer_out = &buffer->srgb.out;
 | 
			
		||||
	} else if (using_linear_pathway) {
 | 
			
		||||
		render_setup = buffer->linear.render_setup;
 | 
			
		||||
		buffer_out = &buffer->linear.out;
 | 
			
		||||
	} else {
 | 
			
		||||
		abort(); // unreachable
 | 
			
		||||
	if (!using_srgb_pathway && !buffer->plain.image_view) {
 | 
			
		||||
		struct wlr_dmabuf_attributes attribs;
 | 
			
		||||
		wlr_buffer_get_dmabuf(buffer->wlr_buffer, &attribs);
 | 
			
		||||
		if (!vulkan_setup_plain_framebuffer(buffer, &attribs)) {
 | 
			
		||||
			wlr_log(WLR_ERROR, "Failed to set up blend image");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_vk_render_pass *pass = calloc(1, sizeof(*pass));
 | 
			
		||||
| 
						 | 
				
			
			@ -1231,7 +1072,7 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
 | 
			
		|||
 | 
			
		||||
	wlr_render_pass_init(&pass->base, &render_pass_impl);
 | 
			
		||||
	pass->renderer = renderer;
 | 
			
		||||
	pass->two_pass = using_two_pass_pathway;
 | 
			
		||||
	pass->srgb_pathway = using_srgb_pathway;
 | 
			
		||||
	if (options != NULL && options->color_transform != NULL) {
 | 
			
		||||
		pass->color_transform = wlr_color_transform_ref(options->color_transform);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1239,10 +1080,6 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
 | 
			
		|||
		pass->signal_timeline = wlr_drm_syncobj_timeline_ref(options->signal_timeline);
 | 
			
		||||
		pass->signal_point = options->signal_point;
 | 
			
		||||
	}
 | 
			
		||||
	if (options != NULL && options->primaries != NULL) {
 | 
			
		||||
		pass->has_primaries = true;
 | 
			
		||||
		pass->primaries = *options->primaries;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rect_union_init(&pass->updated_region);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1279,9 +1116,14 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
 | 
			
		|||
		.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
 | 
			
		||||
		.renderArea = rect,
 | 
			
		||||
		.clearValueCount = 0,
 | 
			
		||||
		.renderPass = render_setup->render_pass,
 | 
			
		||||
		.framebuffer = buffer_out->framebuffer,
 | 
			
		||||
	};
 | 
			
		||||
	if (pass->srgb_pathway) {
 | 
			
		||||
		rp_info.renderPass = buffer->srgb.render_setup->render_pass;
 | 
			
		||||
		rp_info.framebuffer = buffer->srgb.framebuffer;
 | 
			
		||||
	} else {
 | 
			
		||||
		rp_info.renderPass = buffer->plain.render_setup->render_pass;
 | 
			
		||||
		rp_info.framebuffer = buffer->plain.framebuffer;
 | 
			
		||||
	}
 | 
			
		||||
	vkCmdBeginRenderPass(cb->vk, &rp_info, VK_SUBPASS_CONTENTS_INLINE);
 | 
			
		||||
 | 
			
		||||
	vkCmdSetViewport(cb->vk, 0, 1, &(VkViewport){
 | 
			
		||||
| 
						 | 
				
			
			@ -1296,8 +1138,6 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend
 | 
			
		|||
 | 
			
		||||
	wlr_buffer_lock(buffer->wlr_buffer);
 | 
			
		||||
	pass->render_buffer = buffer;
 | 
			
		||||
	pass->render_buffer_out = buffer_out;
 | 
			
		||||
	pass->render_setup = render_setup;
 | 
			
		||||
	pass->command_buffer = cb;
 | 
			
		||||
	return pass;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,72 +66,59 @@ static struct wlr_vk_descriptor_pool *alloc_ds(
 | 
			
		|||
		struct wl_list *pool_list, size_t *last_pool_size) {
 | 
			
		||||
	VkResult res;
 | 
			
		||||
 | 
			
		||||
	bool found = false;
 | 
			
		||||
	struct wlr_vk_descriptor_pool *pool;
 | 
			
		||||
	wl_list_for_each(pool, pool_list, link) {
 | 
			
		||||
		if (pool->free > 0) {
 | 
			
		||||
			found = true;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!found) { // create new pool
 | 
			
		||||
		pool = calloc(1, sizeof(*pool));
 | 
			
		||||
		if (!pool) {
 | 
			
		||||
			wlr_log_errno(WLR_ERROR, "allocation failed");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		size_t count = 2 * (*last_pool_size);
 | 
			
		||||
		if (!count) {
 | 
			
		||||
			count = start_descriptor_pool_size;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pool->free = count;
 | 
			
		||||
		VkDescriptorPoolSize pool_size = {
 | 
			
		||||
			.descriptorCount = count,
 | 
			
		||||
			.type = type,
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		VkDescriptorPoolCreateInfo dpool_info = {
 | 
			
		||||
			.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
 | 
			
		||||
			.maxSets = count,
 | 
			
		||||
			.poolSizeCount = 1,
 | 
			
		||||
			.pPoolSizes = &pool_size,
 | 
			
		||||
			.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		res = vkCreateDescriptorPool(renderer->dev->dev, &dpool_info, NULL,
 | 
			
		||||
			&pool->pool);
 | 
			
		||||
		if (res != VK_SUCCESS) {
 | 
			
		||||
			wlr_vk_error("vkCreateDescriptorPool", res);
 | 
			
		||||
			free(pool);
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		*last_pool_size = count;
 | 
			
		||||
		wl_list_insert(pool_list, &pool->link);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VkDescriptorSetAllocateInfo ds_info = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
 | 
			
		||||
		.descriptorSetCount = 1,
 | 
			
		||||
		.pSetLayouts = layout,
 | 
			
		||||
		.descriptorPool = pool->pool,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct wlr_vk_descriptor_pool *pool;
 | 
			
		||||
	wl_list_for_each(pool, pool_list, link) {
 | 
			
		||||
		if (pool->free > 0) {
 | 
			
		||||
			ds_info.descriptorPool = pool->pool;
 | 
			
		||||
			res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
 | 
			
		||||
			switch (res) {
 | 
			
		||||
			case VK_ERROR_FRAGMENTED_POOL:
 | 
			
		||||
			case VK_ERROR_OUT_OF_POOL_MEMORY:
 | 
			
		||||
				// Descriptor sets with more than one descriptor can cause us
 | 
			
		||||
				// to run out of pool memory early or lead to fragmentation
 | 
			
		||||
				// that makes the pool unable to service our allocation
 | 
			
		||||
				// request. Try the next pool or allocate a new one.
 | 
			
		||||
				continue;
 | 
			
		||||
			case VK_SUCCESS:
 | 
			
		||||
				--pool->free;
 | 
			
		||||
				return pool;
 | 
			
		||||
			default:
 | 
			
		||||
				wlr_vk_error("vkAllocateDescriptorSets", res);
 | 
			
		||||
				return NULL;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pool = calloc(1, sizeof(*pool));
 | 
			
		||||
	if (!pool) {
 | 
			
		||||
		wlr_log_errno(WLR_ERROR, "allocation failed");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t count = 2 * (*last_pool_size);
 | 
			
		||||
	if (!count) {
 | 
			
		||||
		count = start_descriptor_pool_size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pool->free = count;
 | 
			
		||||
	VkDescriptorPoolSize pool_size = {
 | 
			
		||||
		.descriptorCount = count,
 | 
			
		||||
		.type = type,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	VkDescriptorPoolCreateInfo dpool_info = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
 | 
			
		||||
		.maxSets = count,
 | 
			
		||||
		.poolSizeCount = 1,
 | 
			
		||||
		.pPoolSizes = &pool_size,
 | 
			
		||||
		.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	res = vkCreateDescriptorPool(renderer->dev->dev, &dpool_info, NULL,
 | 
			
		||||
		&pool->pool);
 | 
			
		||||
	if (res != VK_SUCCESS) {
 | 
			
		||||
		wlr_vk_error("vkCreateDescriptorPool", res);
 | 
			
		||||
		free(pool);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*last_pool_size = count;
 | 
			
		||||
	wl_list_insert(pool_list, &pool->link);
 | 
			
		||||
 | 
			
		||||
	ds_info.descriptorPool = pool->pool;
 | 
			
		||||
	res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
 | 
			
		||||
	if (res != VK_SUCCESS) {
 | 
			
		||||
		wlr_vk_error("vkAllocateDescriptorSets", res);
 | 
			
		||||
| 
						 | 
				
			
			@ -171,12 +158,8 @@ static void destroy_render_format_setup(struct wlr_vk_renderer *renderer,
 | 
			
		|||
 | 
			
		||||
	VkDevice dev = renderer->dev->dev;
 | 
			
		||||
	vkDestroyRenderPass(dev, setup->render_pass, NULL);
 | 
			
		||||
	vkDestroyPipeline(dev, setup->output_pipe_identity, NULL);
 | 
			
		||||
	vkDestroyPipeline(dev, setup->output_pipe_srgb, NULL);
 | 
			
		||||
	vkDestroyPipeline(dev, setup->output_pipe_pq, NULL);
 | 
			
		||||
	vkDestroyPipeline(dev, setup->output_pipe_lut3d, NULL);
 | 
			
		||||
	vkDestroyPipeline(dev, setup->output_pipe_gamma22, NULL);
 | 
			
		||||
	vkDestroyPipeline(dev, setup->output_pipe_bt1886, NULL);
 | 
			
		||||
 | 
			
		||||
	struct wlr_vk_pipeline *pipeline, *tmp_pipeline;
 | 
			
		||||
	wl_list_for_each_safe(pipeline, tmp_pipeline, &setup->pipelines, link) {
 | 
			
		||||
| 
						 | 
				
			
			@ -606,12 +589,6 @@ void vulkan_reset_command_buffer(struct wlr_vk_command_buffer *cb) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void finish_render_buffer_out(struct wlr_vk_render_buffer_out *out,
 | 
			
		||||
		VkDevice dev) {
 | 
			
		||||
	vkDestroyFramebuffer(dev, out->framebuffer, NULL);
 | 
			
		||||
	vkDestroyImageView(dev, out->image_view, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void destroy_render_buffer(struct wlr_vk_render_buffer *buffer) {
 | 
			
		||||
	wl_list_remove(&buffer->link);
 | 
			
		||||
	wlr_addon_finish(&buffer->addon);
 | 
			
		||||
| 
						 | 
				
			
			@ -625,16 +602,17 @@ static void destroy_render_buffer(struct wlr_vk_render_buffer *buffer) {
 | 
			
		|||
		wlr_vk_error("vkQueueWaitIdle", res);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	finish_render_buffer_out(&buffer->linear.out, dev);
 | 
			
		||||
	finish_render_buffer_out(&buffer->srgb.out, dev);
 | 
			
		||||
	vkDestroyFramebuffer(dev, buffer->srgb.framebuffer, NULL);
 | 
			
		||||
	vkDestroyImageView(dev, buffer->srgb.image_view, NULL);
 | 
			
		||||
 | 
			
		||||
	finish_render_buffer_out(&buffer->two_pass.out, dev);
 | 
			
		||||
	vkDestroyImage(dev, buffer->two_pass.blend_image, NULL);
 | 
			
		||||
	vkFreeMemory(dev, buffer->two_pass.blend_memory, NULL);
 | 
			
		||||
	vkDestroyImageView(dev, buffer->two_pass.blend_image_view, NULL);
 | 
			
		||||
	if (buffer->two_pass.blend_attachment_pool) {
 | 
			
		||||
		vulkan_free_ds(buffer->renderer, buffer->two_pass.blend_attachment_pool,
 | 
			
		||||
			buffer->two_pass.blend_descriptor_set);
 | 
			
		||||
	vkDestroyFramebuffer(dev, buffer->plain.framebuffer, NULL);
 | 
			
		||||
	vkDestroyImageView(dev, buffer->plain.image_view, NULL);
 | 
			
		||||
	vkDestroyImage(dev, buffer->plain.blend_image, NULL);
 | 
			
		||||
	vkFreeMemory(dev, buffer->plain.blend_memory, NULL);
 | 
			
		||||
	vkDestroyImageView(dev, buffer->plain.blend_image_view, NULL);
 | 
			
		||||
	if (buffer->plain.blend_attachment_pool) {
 | 
			
		||||
		vulkan_free_ds(buffer->renderer, buffer->plain.blend_attachment_pool,
 | 
			
		||||
			buffer->plain.blend_descriptor_set);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vkDestroyImage(dev, buffer->image, NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -655,7 +633,7 @@ static struct wlr_addon_interface render_buffer_addon_impl = {
 | 
			
		|||
	.destroy = handle_render_buffer_destroy,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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_renderer *renderer = buffer->renderer;
 | 
			
		||||
	VkResult res;
 | 
			
		||||
| 
						 | 
				
			
			@ -683,15 +661,15 @@ bool vulkan_setup_two_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
 | 
			
		|||
		},
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	res = vkCreateImageView(dev, &view_info, NULL, &buffer->two_pass.out.image_view);
 | 
			
		||||
	res = vkCreateImageView(dev, &view_info, NULL, &buffer->plain.image_view);
 | 
			
		||||
	if (res != VK_SUCCESS) {
 | 
			
		||||
		wlr_vk_error("vkCreateImageView failed", res);
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	buffer->two_pass.render_setup = find_or_create_render_setup(
 | 
			
		||||
	buffer->plain.render_setup = find_or_create_render_setup(
 | 
			
		||||
		renderer, &fmt->format, true);
 | 
			
		||||
	if (!buffer->two_pass.render_setup) {
 | 
			
		||||
	if (!buffer->plain.render_setup) {
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -711,14 +689,14 @@ bool vulkan_setup_two_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
 | 
			
		|||
		.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	res = vkCreateImage(dev, &img_info, NULL, &buffer->two_pass.blend_image);
 | 
			
		||||
	res = vkCreateImage(dev, &img_info, NULL, &buffer->plain.blend_image);
 | 
			
		||||
	if (res != VK_SUCCESS) {
 | 
			
		||||
		wlr_vk_error("vkCreateImage failed", res);
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VkMemoryRequirements mem_reqs;
 | 
			
		||||
	vkGetImageMemoryRequirements(dev, buffer->two_pass.blend_image, &mem_reqs);
 | 
			
		||||
	vkGetImageMemoryRequirements(dev, buffer->plain.blend_image, &mem_reqs);
 | 
			
		||||
 | 
			
		||||
	int mem_type_index = vulkan_find_mem_type(renderer->dev,
 | 
			
		||||
		VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, mem_reqs.memoryTypeBits);
 | 
			
		||||
| 
						 | 
				
			
			@ -733,13 +711,13 @@ bool vulkan_setup_two_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
 | 
			
		|||
		.memoryTypeIndex = mem_type_index,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	res = vkAllocateMemory(dev, &mem_info, NULL, &buffer->two_pass.blend_memory);
 | 
			
		||||
	res = vkAllocateMemory(dev, &mem_info, NULL, &buffer->plain.blend_memory);
 | 
			
		||||
	if (res != VK_SUCCESS) {
 | 
			
		||||
		wlr_vk_error("vkAllocatorMemory failed", res);
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res = vkBindImageMemory(dev, buffer->two_pass.blend_image, buffer->two_pass.blend_memory, 0);
 | 
			
		||||
	res = vkBindImageMemory(dev, buffer->plain.blend_image, buffer->plain.blend_memory, 0);
 | 
			
		||||
	if (res != VK_SUCCESS) {
 | 
			
		||||
		wlr_vk_error("vkBindMemory failed", res);
 | 
			
		||||
		goto error;
 | 
			
		||||
| 
						 | 
				
			
			@ -747,7 +725,7 @@ bool vulkan_setup_two_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
 | 
			
		|||
 | 
			
		||||
	VkImageViewCreateInfo blend_view_info = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
 | 
			
		||||
		.image = buffer->two_pass.blend_image,
 | 
			
		||||
		.image = buffer->plain.blend_image,
 | 
			
		||||
		.viewType = VK_IMAGE_VIEW_TYPE_2D,
 | 
			
		||||
		.format = img_info.format,
 | 
			
		||||
		.components.r = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
			
		||||
| 
						 | 
				
			
			@ -763,50 +741,50 @@ bool vulkan_setup_two_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
 | 
			
		|||
		},
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	res = vkCreateImageView(dev, &blend_view_info, NULL, &buffer->two_pass.blend_image_view);
 | 
			
		||||
	res = vkCreateImageView(dev, &blend_view_info, NULL, &buffer->plain.blend_image_view);
 | 
			
		||||
	if (res != VK_SUCCESS) {
 | 
			
		||||
		wlr_vk_error("vkCreateImageView failed", res);
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	buffer->two_pass.blend_attachment_pool = vulkan_alloc_blend_ds(renderer,
 | 
			
		||||
		&buffer->two_pass.blend_descriptor_set);
 | 
			
		||||
	if (!buffer->two_pass.blend_attachment_pool) {
 | 
			
		||||
	buffer->plain.blend_attachment_pool = vulkan_alloc_blend_ds(renderer,
 | 
			
		||||
		&buffer->plain.blend_descriptor_set);
 | 
			
		||||
	if (!buffer->plain.blend_attachment_pool) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "failed to allocate descriptor");
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VkDescriptorImageInfo ds_attach_info = {
 | 
			
		||||
		.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
 | 
			
		||||
		.imageView = buffer->two_pass.blend_image_view,
 | 
			
		||||
		.imageView = buffer->plain.blend_image_view,
 | 
			
		||||
		.sampler = VK_NULL_HANDLE,
 | 
			
		||||
	};
 | 
			
		||||
	VkWriteDescriptorSet ds_write = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
 | 
			
		||||
		.descriptorCount = 1,
 | 
			
		||||
		.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
 | 
			
		||||
		.dstSet = buffer->two_pass.blend_descriptor_set,
 | 
			
		||||
		.dstSet = buffer->plain.blend_descriptor_set,
 | 
			
		||||
		.dstBinding = 0,
 | 
			
		||||
		.pImageInfo = &ds_attach_info,
 | 
			
		||||
	};
 | 
			
		||||
	vkUpdateDescriptorSets(dev, 1, &ds_write, 0, NULL);
 | 
			
		||||
 | 
			
		||||
	VkImageView attachments[] = {
 | 
			
		||||
		buffer->two_pass.blend_image_view,
 | 
			
		||||
		buffer->two_pass.out.image_view,
 | 
			
		||||
	VkImageView attachments[2] = {
 | 
			
		||||
		buffer->plain.blend_image_view,
 | 
			
		||||
		buffer->plain.image_view
 | 
			
		||||
	};
 | 
			
		||||
	VkFramebufferCreateInfo fb_info = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
 | 
			
		||||
		.attachmentCount = sizeof(attachments) / sizeof(attachments[0]),
 | 
			
		||||
		.attachmentCount = 2,
 | 
			
		||||
		.pAttachments = attachments,
 | 
			
		||||
		.flags = 0u,
 | 
			
		||||
		.width = dmabuf->width,
 | 
			
		||||
		.height = dmabuf->height,
 | 
			
		||||
		.layers = 1u,
 | 
			
		||||
		.renderPass = buffer->two_pass.render_setup->render_pass,
 | 
			
		||||
		.renderPass = buffer->plain.render_setup->render_pass,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->two_pass.out.framebuffer);
 | 
			
		||||
	res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->plain.framebuffer);
 | 
			
		||||
	if (res != VK_SUCCESS) {
 | 
			
		||||
		wlr_vk_error("vkCreateFramebuffer", res);
 | 
			
		||||
		goto error;
 | 
			
		||||
| 
						 | 
				
			
			@ -820,8 +798,8 @@ error:
 | 
			
		|||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
 | 
			
		||||
		const struct wlr_dmabuf_attributes *dmabuf, bool srgb) {
 | 
			
		||||
static bool vulkan_setup_srgb_framebuffer(struct wlr_vk_render_buffer *buffer,
 | 
			
		||||
		const struct wlr_dmabuf_attributes *dmabuf) {
 | 
			
		||||
	struct wlr_vk_renderer *renderer = buffer->renderer;
 | 
			
		||||
	VkResult res;
 | 
			
		||||
	VkDevice dev = renderer->dev->dev;
 | 
			
		||||
| 
						 | 
				
			
			@ -830,18 +808,14 @@ bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
 | 
			
		|||
		renderer->dev, dmabuf->format);
 | 
			
		||||
	assert(fmt);
 | 
			
		||||
 | 
			
		||||
	VkFormat vk_fmt = srgb ? fmt->format.vk_srgb : fmt->format.vk;
 | 
			
		||||
	assert(vk_fmt != VK_FORMAT_UNDEFINED);
 | 
			
		||||
 | 
			
		||||
	struct wlr_vk_render_buffer_out *out = srgb ? &buffer->srgb.out : &buffer->linear.out;
 | 
			
		||||
 | 
			
		||||
	// Set up the srgb framebuffer by default; two-pass framebuffer and
 | 
			
		||||
	assert(fmt->format.vk_srgb);
 | 
			
		||||
	// Set up the srgb framebuffer by default; plain framebuffer and
 | 
			
		||||
	// blending image will be set up later if necessary
 | 
			
		||||
	VkImageViewCreateInfo view_info = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
 | 
			
		||||
		.image = buffer->image,
 | 
			
		||||
		.viewType = VK_IMAGE_VIEW_TYPE_2D,
 | 
			
		||||
		.format = vk_fmt,
 | 
			
		||||
		.format = fmt->format.vk_srgb,
 | 
			
		||||
		.components.r = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
			
		||||
		.components.g = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
			
		||||
		.components.b = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
			
		||||
| 
						 | 
				
			
			@ -855,43 +829,35 @@ bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffer,
 | 
			
		|||
		},
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	res = vkCreateImageView(dev, &view_info, NULL, &out->image_view);
 | 
			
		||||
	res = vkCreateImageView(dev, &view_info, NULL, &buffer->srgb.image_view);
 | 
			
		||||
	if (res != VK_SUCCESS) {
 | 
			
		||||
		wlr_vk_error("vkCreateImageView failed", res);
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_vk_render_format_setup *render_setup =
 | 
			
		||||
		find_or_create_render_setup(renderer, &fmt->format, false);
 | 
			
		||||
	if (!render_setup) {
 | 
			
		||||
	buffer->srgb.render_setup = find_or_create_render_setup(
 | 
			
		||||
		renderer, &fmt->format, false);
 | 
			
		||||
	if (!buffer->srgb.render_setup) {
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VkFramebufferCreateInfo fb_info = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
 | 
			
		||||
		.attachmentCount = 1,
 | 
			
		||||
		.pAttachments = &out->image_view,
 | 
			
		||||
		.pAttachments = &buffer->srgb.image_view,
 | 
			
		||||
		.flags = 0u,
 | 
			
		||||
		.width = dmabuf->width,
 | 
			
		||||
		.height = dmabuf->height,
 | 
			
		||||
		.layers = 1u,
 | 
			
		||||
		.renderPass = render_setup->render_pass,
 | 
			
		||||
		.renderPass = buffer->srgb.render_setup->render_pass,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	res = vkCreateFramebuffer(dev, &fb_info, NULL, &out->framebuffer);
 | 
			
		||||
	res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->srgb.framebuffer);
 | 
			
		||||
	if (res != VK_SUCCESS) {
 | 
			
		||||
		wlr_vk_error("vkCreateFramebuffer", res);
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (srgb) {
 | 
			
		||||
		buffer->srgb.render_setup = render_setup;
 | 
			
		||||
	} else {
 | 
			
		||||
		buffer->linear.render_setup = render_setup;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
 | 
			
		||||
error:
 | 
			
		||||
	// cleaning up everything is the caller's responsibility,
 | 
			
		||||
	// since it will need to do this anyway if framebuffer setup fails
 | 
			
		||||
| 
						 | 
				
			
			@ -935,12 +901,12 @@ static struct wlr_vk_render_buffer *create_render_buffer(
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (using_mutable_srgb) {
 | 
			
		||||
		if (!vulkan_setup_one_pass_framebuffer(buffer, &dmabuf, true)) {
 | 
			
		||||
		if (!vulkan_setup_srgb_framebuffer(buffer, &dmabuf)) {
 | 
			
		||||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		// Set up the two-pass framebuffer & blending image
 | 
			
		||||
		if (!vulkan_setup_two_pass_framebuffer(buffer, &dmabuf)) {
 | 
			
		||||
		// Set up the plain framebuffer & blending image
 | 
			
		||||
		if (!vulkan_setup_plain_framebuffer(buffer, &dmabuf)) {
 | 
			
		||||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1498,14 +1464,14 @@ static bool init_tex_layouts(struct wlr_vk_renderer *renderer,
 | 
			
		|||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VkPushConstantRange pc_ranges[] = {
 | 
			
		||||
	VkPushConstantRange pc_ranges[2] = {
 | 
			
		||||
		{
 | 
			
		||||
			.size = sizeof(struct wlr_vk_vert_pcr_data),
 | 
			
		||||
			.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			.offset = pc_ranges[0].size,
 | 
			
		||||
			.size = sizeof(struct wlr_vk_frag_texture_pcr_data),
 | 
			
		||||
			.size = sizeof(float) * 4, // alpha or color
 | 
			
		||||
			.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
 | 
			
		||||
		},
 | 
			
		||||
	};
 | 
			
		||||
| 
						 | 
				
			
			@ -1514,7 +1480,7 @@ static bool init_tex_layouts(struct wlr_vk_renderer *renderer,
 | 
			
		|||
		.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
 | 
			
		||||
		.setLayoutCount = 1,
 | 
			
		||||
		.pSetLayouts = out_ds_layout,
 | 
			
		||||
		.pushConstantRangeCount = sizeof(pc_ranges) / sizeof(pc_ranges[0]),
 | 
			
		||||
		.pushConstantRangeCount = 2,
 | 
			
		||||
		.pPushConstantRanges = pc_ranges,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1592,7 +1558,7 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// pipeline layout -- standard vertex uniforms, no shader uniforms
 | 
			
		||||
	VkPushConstantRange pc_ranges[] = {
 | 
			
		||||
	VkPushConstantRange pc_ranges[2] = {
 | 
			
		||||
		{
 | 
			
		||||
			.offset = 0,
 | 
			
		||||
			.size = sizeof(struct wlr_vk_vert_pcr_data),
 | 
			
		||||
| 
						 | 
				
			
			@ -1605,16 +1571,16 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) {
 | 
			
		|||
		},
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	VkDescriptorSetLayout out_ds_layouts[] = {
 | 
			
		||||
	VkDescriptorSetLayout out_ds_layouts[2] = {
 | 
			
		||||
		renderer->output_ds_srgb_layout,
 | 
			
		||||
		renderer->output_ds_lut3d_layout,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	VkPipelineLayoutCreateInfo pl_info = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
 | 
			
		||||
		.setLayoutCount = sizeof(out_ds_layouts) / sizeof(out_ds_layouts[0]),
 | 
			
		||||
		.setLayoutCount = 2,
 | 
			
		||||
		.pSetLayouts = out_ds_layouts,
 | 
			
		||||
		.pushConstantRangeCount = sizeof(pc_ranges) / sizeof(pc_ranges[0]),
 | 
			
		||||
		.pushConstantRangeCount = 2,
 | 
			
		||||
		.pPushConstantRanges = pc_ranges,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1787,14 +1753,14 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline(
 | 
			
		|||
		.scissorCount = 1,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	VkDynamicState dyn_states[] = {
 | 
			
		||||
	VkDynamicState dynStates[2] = {
 | 
			
		||||
		VK_DYNAMIC_STATE_VIEWPORT,
 | 
			
		||||
		VK_DYNAMIC_STATE_SCISSOR,
 | 
			
		||||
	};
 | 
			
		||||
	VkPipelineDynamicStateCreateInfo dynamic = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
 | 
			
		||||
		.pDynamicStates = dyn_states,
 | 
			
		||||
		.dynamicStateCount = sizeof(dyn_states) / sizeof(dyn_states[0]),
 | 
			
		||||
		.pDynamicStates = dynStates,
 | 
			
		||||
		.dynamicStateCount = 2,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	VkPipelineVertexInputStateCreateInfo vertex = {
 | 
			
		||||
| 
						 | 
				
			
			@ -1806,7 +1772,7 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline(
 | 
			
		|||
		.layout = pipeline_layout->vk,
 | 
			
		||||
		.renderPass = setup->render_pass,
 | 
			
		||||
		.subpass = 0,
 | 
			
		||||
		.stageCount = sizeof(stages) / sizeof(stages[0]),
 | 
			
		||||
		.stageCount = 2,
 | 
			
		||||
		.pStages = stages,
 | 
			
		||||
 | 
			
		||||
		.pInputAssemblyState = &assembly,
 | 
			
		||||
| 
						 | 
				
			
			@ -1849,7 +1815,7 @@ static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer,
 | 
			
		|||
		.pData = &output_transform_type,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	VkPipelineShaderStageCreateInfo tex_stages[] = {
 | 
			
		||||
	VkPipelineShaderStageCreateInfo tex_stages[2] = {
 | 
			
		||||
		{
 | 
			
		||||
			.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
 | 
			
		||||
			.stage = VK_SHADER_STAGE_VERTEX_BIT,
 | 
			
		||||
| 
						 | 
				
			
			@ -1904,14 +1870,14 @@ static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer,
 | 
			
		|||
		.scissorCount = 1,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	VkDynamicState dyn_states[] = {
 | 
			
		||||
	VkDynamicState dynStates[2] = {
 | 
			
		||||
		VK_DYNAMIC_STATE_VIEWPORT,
 | 
			
		||||
		VK_DYNAMIC_STATE_SCISSOR,
 | 
			
		||||
	};
 | 
			
		||||
	VkPipelineDynamicStateCreateInfo dynamic = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
 | 
			
		||||
		.pDynamicStates = dyn_states,
 | 
			
		||||
		.dynamicStateCount = sizeof(dyn_states) / sizeof(dyn_states[0]),
 | 
			
		||||
		.pDynamicStates = dynStates,
 | 
			
		||||
		.dynamicStateCount = 2,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	VkPipelineVertexInputStateCreateInfo vertex = {
 | 
			
		||||
| 
						 | 
				
			
			@ -1924,7 +1890,7 @@ static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer,
 | 
			
		|||
		.layout = pipe_layout,
 | 
			
		||||
		.renderPass = rp,
 | 
			
		||||
		.subpass = 1, // second subpass!
 | 
			
		||||
		.stageCount = sizeof(tex_stages) / sizeof(tex_stages[0]),
 | 
			
		||||
		.stageCount = 2,
 | 
			
		||||
		.pStages = tex_stages,
 | 
			
		||||
		.pInputAssemblyState = &assembly,
 | 
			
		||||
		.pRasterizationState = &rasterization,
 | 
			
		||||
| 
						 | 
				
			
			@ -2217,7 +2183,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
 | 
			
		|||
	VkResult res;
 | 
			
		||||
 | 
			
		||||
	if (use_blending_buffer) {
 | 
			
		||||
		VkAttachmentDescription attachments[] = {
 | 
			
		||||
		VkAttachmentDescription attachments[2] = {
 | 
			
		||||
			{
 | 
			
		||||
				.format = VK_FORMAT_R16G16B16A16_SFLOAT,
 | 
			
		||||
				.samples = VK_SAMPLE_COUNT_1_BIT,
 | 
			
		||||
| 
						 | 
				
			
			@ -2255,7 +2221,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
 | 
			
		|||
			.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		VkSubpassDescription subpasses[] = {
 | 
			
		||||
		VkSubpassDescription subpasses[2] = {
 | 
			
		||||
			{
 | 
			
		||||
				.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
 | 
			
		||||
				.colorAttachmentCount = 1,
 | 
			
		||||
| 
						 | 
				
			
			@ -2270,7 +2236,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
 | 
			
		|||
			}
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		VkSubpassDependency deps[] = {
 | 
			
		||||
		VkSubpassDependency deps[3] = {
 | 
			
		||||
			{
 | 
			
		||||
				.srcSubpass = VK_SUBPASS_EXTERNAL,
 | 
			
		||||
				.srcStageMask = VK_PIPELINE_STAGE_HOST_BIT |
 | 
			
		||||
| 
						 | 
				
			
			@ -2312,11 +2278,11 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
 | 
			
		|||
			.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
 | 
			
		||||
			.pNext = NULL,
 | 
			
		||||
			.flags = 0,
 | 
			
		||||
			.attachmentCount = sizeof(attachments) / sizeof(attachments[0]),
 | 
			
		||||
			.attachmentCount = 2u,
 | 
			
		||||
			.pAttachments = attachments,
 | 
			
		||||
			.subpassCount = sizeof(subpasses) / sizeof(subpasses[0]),
 | 
			
		||||
			.subpassCount = 2u,
 | 
			
		||||
			.pSubpasses = subpasses,
 | 
			
		||||
			.dependencyCount = sizeof(deps) / sizeof(deps[0]),
 | 
			
		||||
			.dependencyCount = 3u,
 | 
			
		||||
			.pDependencies = deps,
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2327,34 +2293,14 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		// this is only well defined if render pass has a 2nd subpass
 | 
			
		||||
		if (!init_blend_to_output_pipeline(
 | 
			
		||||
				renderer, setup->render_pass, renderer->output_pipe_layout,
 | 
			
		||||
				&setup->output_pipe_identity, WLR_VK_OUTPUT_TRANSFORM_IDENTITY)) {
 | 
			
		||||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
		if (!init_blend_to_output_pipeline(
 | 
			
		||||
				renderer, setup->render_pass, renderer->output_pipe_layout,
 | 
			
		||||
				&setup->output_pipe_lut3d, WLR_VK_OUTPUT_TRANSFORM_LUT3D)) {
 | 
			
		||||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
		if (!init_blend_to_output_pipeline(
 | 
			
		||||
				renderer, setup->render_pass, renderer->output_pipe_layout,
 | 
			
		||||
				&setup->output_pipe_srgb, WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB)) {
 | 
			
		||||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
		if (!init_blend_to_output_pipeline(
 | 
			
		||||
				renderer, setup->render_pass, renderer->output_pipe_layout,
 | 
			
		||||
				&setup->output_pipe_pq, WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ)) {
 | 
			
		||||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
		if (!init_blend_to_output_pipeline(
 | 
			
		||||
				renderer, setup->render_pass, renderer->output_pipe_layout,
 | 
			
		||||
				&setup->output_pipe_gamma22, WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22)) {
 | 
			
		||||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
		if (!init_blend_to_output_pipeline(
 | 
			
		||||
			renderer, setup->render_pass, renderer->output_pipe_layout,
 | 
			
		||||
			&setup->output_pipe_bt1886, WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886)) {
 | 
			
		||||
			&setup->output_pipe_srgb, WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB)) {
 | 
			
		||||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -2381,7 +2327,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
 | 
			
		|||
			.pColorAttachments = &color_ref,
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		VkSubpassDependency deps[] = {
 | 
			
		||||
		VkSubpassDependency deps[2] = {
 | 
			
		||||
			{
 | 
			
		||||
				.srcSubpass = VK_SUBPASS_EXTERNAL,
 | 
			
		||||
				.srcStageMask = VK_PIPELINE_STAGE_HOST_BIT |
 | 
			
		||||
| 
						 | 
				
			
			@ -2416,7 +2362,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
 | 
			
		|||
			.pAttachments = &attachment,
 | 
			
		||||
			.subpassCount = 1,
 | 
			
		||||
			.pSubpasses = &subpass,
 | 
			
		||||
			.dependencyCount = sizeof(deps) / sizeof(deps[0]),
 | 
			
		||||
			.dependencyCount = 2u,
 | 
			
		||||
			.pDependencies = deps,
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2484,7 +2430,6 @@ struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev
 | 
			
		|||
 | 
			
		||||
	renderer->dev = dev;
 | 
			
		||||
	wlr_renderer_init(&renderer->wlr_renderer, &renderer_impl, WLR_BUFFER_CAP_DMABUF);
 | 
			
		||||
	renderer->wlr_renderer.features.input_color_transform = true;
 | 
			
		||||
	renderer->wlr_renderer.features.output_color_transform = true;
 | 
			
		||||
	wl_list_init(&renderer->stage.buffers);
 | 
			
		||||
	wl_list_init(&renderer->foreign_textures);
 | 
			
		||||
| 
						 | 
				
			
			@ -2556,13 +2501,14 @@ struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd) {
 | 
			
		|||
	if (!phdev) {
 | 
			
		||||
		// We rather fail here than doing some guesswork
 | 
			
		||||
		wlr_log(WLR_ERROR, "Could not match drm and vulkan device");
 | 
			
		||||
		goto error;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_vk_device *dev = vulkan_device_create(ini, phdev);
 | 
			
		||||
	if (!dev) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "Failed to create vulkan device");
 | 
			
		||||
		goto error;
 | 
			
		||||
		vulkan_instance_destroy(ini);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Do not use the drm_fd that was passed in: we should prefer the render
 | 
			
		||||
| 
						 | 
				
			
			@ -2570,10 +2516,6 @@ struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd) {
 | 
			
		|||
	dev->drm_fd = vulkan_open_phdev_drm_fd(phdev);
 | 
			
		||||
 | 
			
		||||
	return vulkan_renderer_create_for_device(dev);
 | 
			
		||||
 | 
			
		||||
error:
 | 
			
		||||
	vulkan_instance_destroy(ini);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VkInstance wlr_vk_renderer_get_instance(struct wlr_renderer *renderer) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,22 +8,16 @@ layout(location = 0) in vec2 uv;
 | 
			
		|||
layout(location = 0) out vec4 out_color;
 | 
			
		||||
 | 
			
		||||
/* struct wlr_vk_frag_output_pcr_data */
 | 
			
		||||
layout(push_constant, row_major) uniform UBO {
 | 
			
		||||
	layout(offset = 80) mat4 matrix;
 | 
			
		||||
	float luminance_multiplier;
 | 
			
		||||
	float lut_3d_offset;
 | 
			
		||||
layout(push_constant) uniform UBO {
 | 
			
		||||
	layout(offset = 80) float lut_3d_offset;
 | 
			
		||||
	float lut_3d_scale;
 | 
			
		||||
} data;
 | 
			
		||||
 | 
			
		||||
layout (constant_id = 0) const int OUTPUT_TRANSFORM = 0;
 | 
			
		||||
 | 
			
		||||
// Matches enum wlr_vk_output_transform
 | 
			
		||||
#define OUTPUT_TRANSFORM_IDENTITY 0
 | 
			
		||||
#define OUTPUT_TRANSFORM_INVERSE_SRGB 1
 | 
			
		||||
#define OUTPUT_TRANSFORM_INVERSE_ST2084_PQ 2
 | 
			
		||||
#define OUTPUT_TRANSFORM_LUT_3D 3
 | 
			
		||||
#define OUTPUT_TRANSFORM_INVERSE_GAMMA22 4
 | 
			
		||||
#define OUTPUT_TRANSFORM_INVERSE_BT1886 5
 | 
			
		||||
#define OUTPUT_TRANSFORM_INVERSE_SRGB 0
 | 
			
		||||
#define OUTPUT_TRANSFORM_LUT_3D 1
 | 
			
		||||
 | 
			
		||||
float linear_channel_to_srgb(float x) {
 | 
			
		||||
	return max(min(x * 12.92, 0.04045), 1.055 * pow(x, 1. / 2.4) - 0.055);
 | 
			
		||||
| 
						 | 
				
			
			@ -37,25 +31,6 @@ vec3 linear_color_to_srgb(vec3 color) {
 | 
			
		|||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3 linear_color_to_pq(vec3 color) {
 | 
			
		||||
	// H.273 TransferCharacteristics code point 16
 | 
			
		||||
	float c1 = 0.8359375;
 | 
			
		||||
	float c2 = 18.8515625;
 | 
			
		||||
	float c3 = 18.6875;
 | 
			
		||||
	float m = 78.84375;
 | 
			
		||||
	float n = 0.1593017578125;
 | 
			
		||||
	vec3 pow_n = pow(clamp(color, vec3(0), vec3(1)), vec3(n));
 | 
			
		||||
	return pow((vec3(c1) + c2 * pow_n) / (vec3(1) + c3 * pow_n), vec3(m));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3 linear_color_to_bt1886(vec3 color) {
 | 
			
		||||
	float lb = pow(0.0001, 1.0 / 2.4);
 | 
			
		||||
	float lw = pow(1.0, 1.0 / 2.4);
 | 
			
		||||
	float a  = pow(lw - lb, 2.4);
 | 
			
		||||
	float b  = lb / (lw - lb);
 | 
			
		||||
	return pow(color / a, vec3(1.0 / 2.4)) - vec3(b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
	vec4 in_color = subpassLoad(in_color).rgba;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -68,26 +43,13 @@ void main() {
 | 
			
		|||
		rgb = in_color.rgb / alpha;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rgb *= data.luminance_multiplier;
 | 
			
		||||
 | 
			
		||||
	rgb = mat3(data.matrix) * rgb;
 | 
			
		||||
 | 
			
		||||
	if (OUTPUT_TRANSFORM != OUTPUT_TRANSFORM_IDENTITY) {
 | 
			
		||||
		rgb = max(rgb, vec3(0));
 | 
			
		||||
	}
 | 
			
		||||
	if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_LUT_3D) {
 | 
			
		||||
		// Apply 3D LUT
 | 
			
		||||
		vec3 pos = data.lut_3d_offset + rgb * data.lut_3d_scale;
 | 
			
		||||
		rgb = texture(lut_3d, pos).rgb;
 | 
			
		||||
	} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_ST2084_PQ) {
 | 
			
		||||
		rgb = linear_color_to_pq(rgb);
 | 
			
		||||
	} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_SRGB) {
 | 
			
		||||
	} else { // OUTPUT_TRANSFORM_INVERSE_SRGB
 | 
			
		||||
		// Produce sRGB encoded values
 | 
			
		||||
		rgb = linear_color_to_srgb(rgb);
 | 
			
		||||
	} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_GAMMA22) {
 | 
			
		||||
		rgb = pow(rgb, vec3(1. / 2.2));
 | 
			
		||||
	} else if (OUTPUT_TRANSFORM == OUTPUT_TRANSFORM_INVERSE_BT1886) {
 | 
			
		||||
		rgb = linear_color_to_bt1886(rgb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Back to pre-multiplied alpha
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,11 +5,8 @@ layout(set = 0, binding = 0) uniform sampler2D tex;
 | 
			
		|||
layout(location = 0) in vec2 uv;
 | 
			
		||||
layout(location = 0) out vec4 out_color;
 | 
			
		||||
 | 
			
		||||
// struct wlr_vk_frag_texture_pcr_data
 | 
			
		||||
layout(push_constant, row_major) uniform UBO {
 | 
			
		||||
	layout(offset = 80) mat4 matrix;
 | 
			
		||||
	float alpha;
 | 
			
		||||
	float luminance_multiplier;
 | 
			
		||||
layout(push_constant) uniform UBO {
 | 
			
		||||
	layout(offset = 80) float alpha;
 | 
			
		||||
} data;
 | 
			
		||||
 | 
			
		||||
layout (constant_id = 0) const int TEXTURE_TRANSFORM = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -17,9 +14,6 @@ layout (constant_id = 0) const int TEXTURE_TRANSFORM = 0;
 | 
			
		|||
// Matches enum wlr_vk_texture_transform
 | 
			
		||||
#define TEXTURE_TRANSFORM_IDENTITY 0
 | 
			
		||||
#define TEXTURE_TRANSFORM_SRGB 1
 | 
			
		||||
#define TEXTURE_TRANSFORM_ST2084_PQ 2
 | 
			
		||||
#define TEXTURE_TRANSFORM_GAMMA22 3
 | 
			
		||||
#define TEXTURE_TRANSFORM_BT1886 4
 | 
			
		||||
 | 
			
		||||
float srgb_channel_to_linear(float x) {
 | 
			
		||||
	return mix(x / 12.92,
 | 
			
		||||
| 
						 | 
				
			
			@ -27,64 +21,27 @@ float srgb_channel_to_linear(float x) {
 | 
			
		|||
		x > 0.04045);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3 srgb_color_to_linear(vec3 color) {
 | 
			
		||||
	return vec3(
 | 
			
		||||
vec4 srgb_color_to_linear(vec4 color) {
 | 
			
		||||
	if (color.a == 0) {
 | 
			
		||||
		return vec4(0);
 | 
			
		||||
	}
 | 
			
		||||
	color.rgb /= color.a;
 | 
			
		||||
	color.rgb = vec3(
 | 
			
		||||
		srgb_channel_to_linear(color.r),
 | 
			
		||||
		srgb_channel_to_linear(color.g),
 | 
			
		||||
		srgb_channel_to_linear(color.b)
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3 pq_color_to_linear(vec3 color) {
 | 
			
		||||
	float inv_m1 = 1 / 0.1593017578125;
 | 
			
		||||
	float inv_m2 = 1 / 78.84375;
 | 
			
		||||
	float c1 = 0.8359375;
 | 
			
		||||
	float c2 = 18.8515625;
 | 
			
		||||
	float c3 = 18.6875;
 | 
			
		||||
	vec3 num = max(pow(color, vec3(inv_m2)) - c1, 0);
 | 
			
		||||
	vec3 denom = c2 - c3 * pow(color, vec3(inv_m2));
 | 
			
		||||
	return pow(num / denom, vec3(inv_m1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3 bt1886_color_to_linear(vec3 color) {
 | 
			
		||||
	float lb = pow(0.0001, 1.0 / 2.4);
 | 
			
		||||
	float lw = pow(1.0, 1.0 / 2.4);
 | 
			
		||||
	float a  = pow(lw - lb, 2.4);
 | 
			
		||||
	float b  = lb / (lw - lb);
 | 
			
		||||
	return a * pow(color + vec3(b), vec3(2.4));
 | 
			
		||||
	color.rgb *= color.a;
 | 
			
		||||
	return color;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
	vec4 in_color = textureLod(tex, uv, 0);
 | 
			
		||||
 | 
			
		||||
	// Convert from pre-multiplied alpha to straight alpha
 | 
			
		||||
	float alpha = in_color.a;
 | 
			
		||||
	vec3 rgb;
 | 
			
		||||
	if (alpha == 0) {
 | 
			
		||||
		rgb = vec3(0);
 | 
			
		||||
	} else {
 | 
			
		||||
		rgb = in_color.rgb / alpha;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (TEXTURE_TRANSFORM != TEXTURE_TRANSFORM_IDENTITY) {
 | 
			
		||||
		rgb = max(rgb, vec3(0));
 | 
			
		||||
	}
 | 
			
		||||
	vec4 val = textureLod(tex, uv, 0);
 | 
			
		||||
	if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_SRGB) {
 | 
			
		||||
		rgb = srgb_color_to_linear(rgb);
 | 
			
		||||
	} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_ST2084_PQ) {
 | 
			
		||||
		rgb = pq_color_to_linear(rgb);
 | 
			
		||||
	} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_GAMMA22) {
 | 
			
		||||
		rgb = pow(rgb, vec3(2.2));
 | 
			
		||||
	} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_BT1886) {
 | 
			
		||||
		rgb = bt1886_color_to_linear(rgb);
 | 
			
		||||
		out_color = srgb_color_to_linear(val);
 | 
			
		||||
	} else { // TEXTURE_TRANSFORM_IDENTITY
 | 
			
		||||
		out_color = val;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rgb *= data.luminance_multiplier;
 | 
			
		||||
 | 
			
		||||
	rgb = mat3(data.matrix) * rgb;
 | 
			
		||||
 | 
			
		||||
	// Back to pre-multiplied alpha
 | 
			
		||||
	out_color = vec4(rgb * alpha, alpha);
 | 
			
		||||
 | 
			
		||||
	out_color *= data.alpha;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -269,12 +269,10 @@ static struct wlr_vk_texture *vulkan_texture_create(
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_texture *texture,
 | 
			
		||||
		const struct wlr_vk_pipeline_layout *pipeline_layout, bool srgb) {
 | 
			
		||||
	assert(texture->using_mutable_srgb || !srgb);
 | 
			
		||||
 | 
			
		||||
		const struct wlr_vk_pipeline_layout *pipeline_layout) {
 | 
			
		||||
	struct wlr_vk_texture_view *view;
 | 
			
		||||
	wl_list_for_each(view, &texture->views, link) {
 | 
			
		||||
		if (view->layout == pipeline_layout && view->srgb == srgb) {
 | 
			
		||||
		if (view->layout == pipeline_layout) {
 | 
			
		||||
			return view;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -285,7 +283,6 @@ struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_text
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	view->layout = pipeline_layout;
 | 
			
		||||
	view->srgb = srgb;
 | 
			
		||||
 | 
			
		||||
	VkResult res;
 | 
			
		||||
	VkDevice dev = texture->renderer->dev->dev;
 | 
			
		||||
| 
						 | 
				
			
			@ -293,7 +290,8 @@ struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_text
 | 
			
		|||
	VkImageViewCreateInfo view_info = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
 | 
			
		||||
		.viewType = VK_IMAGE_VIEW_TYPE_2D,
 | 
			
		||||
		.format = srgb ? texture->format->vk_srgb : texture->format->vk,
 | 
			
		||||
		.format = texture->using_mutable_srgb ? texture->format->vk_srgb
 | 
			
		||||
			: texture->format->vk,
 | 
			
		||||
		.components.r = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
			
		||||
		.components.g = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
			
		||||
		.components.b = VK_COMPONENT_SWIZZLE_IDENTITY,
 | 
			
		||||
| 
						 | 
				
			
			@ -355,10 +353,10 @@ struct wlr_vk_texture_view *vulkan_texture_get_or_create_view(struct wlr_vk_text
 | 
			
		|||
 | 
			
		||||
static void texture_set_format(struct wlr_vk_texture *texture,
 | 
			
		||||
		const struct wlr_vk_format *format, bool has_mutable_srgb) {
 | 
			
		||||
	assert(!(format->is_ycbcr && has_mutable_srgb));
 | 
			
		||||
 | 
			
		||||
	texture->format = format;
 | 
			
		||||
	texture->using_mutable_srgb = has_mutable_srgb;
 | 
			
		||||
	texture->transform = !format->is_ycbcr && has_mutable_srgb ?
 | 
			
		||||
		WLR_VK_TEXTURE_TRANSFORM_IDENTITY : WLR_VK_TEXTURE_TRANSFORM_SRGB;
 | 
			
		||||
 | 
			
		||||
	const struct wlr_pixel_format_info *format_info =
 | 
			
		||||
		drm_get_pixel_format_info(format->drm);
 | 
			
		||||
| 
						 | 
				
			
			@ -399,14 +397,14 @@ static struct wlr_texture *vulkan_texture_from_pixels(
 | 
			
		|||
 | 
			
		||||
	texture_set_format(texture, &fmt->format, fmt->shm.has_mutable_srgb);
 | 
			
		||||
 | 
			
		||||
	VkFormat view_formats[] = {
 | 
			
		||||
	VkFormat view_formats[2] = {
 | 
			
		||||
		fmt->format.vk,
 | 
			
		||||
		fmt->format.vk_srgb,
 | 
			
		||||
	};
 | 
			
		||||
	VkImageFormatListCreateInfoKHR list_info = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
 | 
			
		||||
		.pViewFormats = view_formats,
 | 
			
		||||
		.viewFormatCount = sizeof(view_formats) / sizeof(view_formats[0]),
 | 
			
		||||
		.viewFormatCount = 2,
 | 
			
		||||
	};
 | 
			
		||||
	VkImageCreateInfo img_info = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
 | 
			
		||||
| 
						 | 
				
			
			@ -600,14 +598,14 @@ VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer,
 | 
			
		|||
	};
 | 
			
		||||
	eimg.pNext = &mod_info;
 | 
			
		||||
 | 
			
		||||
	VkFormat view_formats[] = {
 | 
			
		||||
	VkFormat view_formats[2] = {
 | 
			
		||||
		fmt->format.vk,
 | 
			
		||||
		fmt->format.vk_srgb,
 | 
			
		||||
	};
 | 
			
		||||
	VkImageFormatListCreateInfoKHR list_info = {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
 | 
			
		||||
		.pViewFormats = view_formats,
 | 
			
		||||
		.viewFormatCount = sizeof(view_formats) / sizeof(view_formats[0]),
 | 
			
		||||
		.viewFormatCount = 2,
 | 
			
		||||
	};
 | 
			
		||||
	if (mod->has_mutable_srgb) {
 | 
			
		||||
		mod_info.pNext = &list_info;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,18 +1,27 @@
 | 
			
		|||
PKG_CONFIG?=pkg-config
 | 
			
		||||
WAYLAND_PROTOCOLS!=$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols
 | 
			
		||||
WAYLAND_SCANNER!=$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner
 | 
			
		||||
 | 
			
		||||
PKGS="wlroots-0.20" wayland-server xkbcommon
 | 
			
		||||
PKGS="wlroots-0.19" wayland-server xkbcommon
 | 
			
		||||
CFLAGS_PKG_CONFIG!=$(PKG_CONFIG) --cflags $(PKGS)
 | 
			
		||||
CFLAGS+=$(CFLAGS_PKG_CONFIG)
 | 
			
		||||
LIBS!=$(PKG_CONFIG) --libs $(PKGS)
 | 
			
		||||
 | 
			
		||||
all: tinywl
 | 
			
		||||
 | 
			
		||||
tinywl.o: tinywl.c
 | 
			
		||||
# wayland-scanner is a tool which generates C headers and rigging for Wayland
 | 
			
		||||
# protocols, which are specified in XML. wlroots requires you to rig these up
 | 
			
		||||
# to your build system yourself and provide them in the include path.
 | 
			
		||||
xdg-shell-protocol.h:
 | 
			
		||||
	$(WAYLAND_SCANNER) server-header \
 | 
			
		||||
		$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
 | 
			
		||||
 | 
			
		||||
tinywl.o: tinywl.c xdg-shell-protocol.h
 | 
			
		||||
	$(CC) -c $< -g -Werror $(CFLAGS) -I. -DWLR_USE_UNSTABLE -o $@
 | 
			
		||||
tinywl: tinywl.o
 | 
			
		||||
	$(CC) $^ $> -g -Werror $(CFLAGS) $(LDFLAGS) $(LIBS) -o $@
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -f tinywl tinywl.o
 | 
			
		||||
	rm -f tinywl tinywl.o xdg-shell-protocol.h
 | 
			
		||||
 | 
			
		||||
.PHONY: all clean
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
executable(
 | 
			
		||||
	'tinywl',
 | 
			
		||||
	'tinywl.c',
 | 
			
		||||
	['tinywl.c', protocols_server_header['xdg-shell']],
 | 
			
		||||
	dependencies: wlroots,
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,7 +56,6 @@ struct tinywl_server {
 | 
			
		|||
	struct wlr_seat *seat;
 | 
			
		||||
	struct wl_listener new_input;
 | 
			
		||||
	struct wl_listener request_cursor;
 | 
			
		||||
	struct wl_listener pointer_focus_change;
 | 
			
		||||
	struct wl_listener request_set_selection;
 | 
			
		||||
	struct wl_list keyboards;
 | 
			
		||||
	enum tinywl_cursor_mode cursor_mode;
 | 
			
		||||
| 
						 | 
				
			
			@ -334,18 +333,6 @@ static void seat_request_cursor(struct wl_listener *listener, void *data) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void seat_pointer_focus_change(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct tinywl_server *server = wl_container_of(
 | 
			
		||||
			listener, server, pointer_focus_change);
 | 
			
		||||
	/* This event is raised when the pointer focus is changed, including when the
 | 
			
		||||
	 * client is closed. We set the cursor image to its default if target surface
 | 
			
		||||
	 * is NULL */
 | 
			
		||||
	struct wlr_seat_pointer_focus_change_event *event = data;
 | 
			
		||||
	if (event->new_surface == NULL) {
 | 
			
		||||
		wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "default");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void seat_request_set_selection(struct wl_listener *listener, void *data) {
 | 
			
		||||
	/* This event is raised by the seat when a client wants to set the selection,
 | 
			
		||||
	 * usually when the user copies something. wlroots allows compositors to
 | 
			
		||||
| 
						 | 
				
			
			@ -1031,9 +1018,6 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
	server.request_cursor.notify = seat_request_cursor;
 | 
			
		||||
	wl_signal_add(&server.seat->events.request_set_cursor,
 | 
			
		||||
			&server.request_cursor);
 | 
			
		||||
	server.pointer_focus_change.notify = seat_pointer_focus_change;
 | 
			
		||||
	wl_signal_add(&server.seat->pointer_state.events.focus_change,
 | 
			
		||||
			&server.pointer_focus_change);
 | 
			
		||||
	server.request_set_selection.notify = seat_request_set_selection;
 | 
			
		||||
	wl_signal_add(&server.seat->events.request_set_selection,
 | 
			
		||||
			&server.request_set_selection);
 | 
			
		||||
| 
						 | 
				
			
			@ -1085,7 +1069,6 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
 | 
			
		||||
	wl_list_remove(&server.new_input.link);
 | 
			
		||||
	wl_list_remove(&server.request_cursor.link);
 | 
			
		||||
	wl_list_remove(&server.pointer_focus_change.link);
 | 
			
		||||
	wl_list_remove(&server.request_set_selection.link);
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&server.new_output.link);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -308,14 +308,6 @@ static void drag_handle_touch_motion(struct wlr_seat_touch_grab *grab,
 | 
			
		|||
				wl_fixed_from_double(point->sx),
 | 
			
		||||
				wl_fixed_from_double(point->sy));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		struct wlr_drag_motion_event event = {
 | 
			
		||||
			.drag = drag,
 | 
			
		||||
			.time = time,
 | 
			
		||||
			.sx = point->sx,
 | 
			
		||||
			.sy = point->sy,
 | 
			
		||||
		};
 | 
			
		||||
		wl_signal_emit_mutable(&drag->events.motion, &event);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,6 @@
 | 
			
		|||
#include <wlr/types/wlr_ext_image_capture_source_v1.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
#include "ext-image-capture-source-v1-protocol.h"
 | 
			
		||||
#include "render/wlr_renderer.h"
 | 
			
		||||
 | 
			
		||||
static void source_handle_destroy(struct wl_client *client,
 | 
			
		||||
		struct wl_resource *source_resource) {
 | 
			
		||||
| 
						 | 
				
			
			@ -97,12 +96,6 @@ static uint32_t get_swapchain_shm_format(struct wlr_swapchain *swapchain,
 | 
			
		|||
	return format;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void add_drm_format(struct wlr_drm_format_set *set, const struct wlr_drm_format *fmt) {
 | 
			
		||||
	for (size_t i = 0; i < fmt->len; i++) {
 | 
			
		||||
		wlr_drm_format_set_add(set, fmt->format, fmt->modifiers[i]);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
	source->width = swapchain->width;
 | 
			
		||||
| 
						 | 
				
			
			@ -137,21 +130,9 @@ bool wlr_ext_image_capture_source_v1_set_constraints_from_swapchain(struct wlr_e
 | 
			
		|||
		wlr_drm_format_set_finish(&source->dmabuf_formats);
 | 
			
		||||
		source->dmabuf_formats = (struct wlr_drm_format_set){0};
 | 
			
		||||
 | 
			
		||||
		add_drm_format(&source->dmabuf_formats, &swapchain->format);
 | 
			
		||||
 | 
			
		||||
		const struct wlr_drm_format_set *render_formats =
 | 
			
		||||
			wlr_renderer_get_render_formats(renderer);
 | 
			
		||||
		assert(render_formats != NULL);
 | 
			
		||||
 | 
			
		||||
		// Not all clients support fancy formats. Always ensure we provide
 | 
			
		||||
		// support for ARGB8888 and XRGB8888 for simple clients.
 | 
			
		||||
		uint32_t fallback_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888 };
 | 
			
		||||
		for (size_t i = 0; i < sizeof(fallback_formats) / sizeof(fallback_formats[0]); i++) {
 | 
			
		||||
			const struct wlr_drm_format *fmt =
 | 
			
		||||
				wlr_drm_format_set_get(render_formats, fallback_formats[i]);
 | 
			
		||||
			if (fmt != NULL && swapchain->format.format != fmt->format) {
 | 
			
		||||
				add_drm_format(&source->dmabuf_formats, fmt);
 | 
			
		||||
			}
 | 
			
		||||
		for (size_t i = 0; i < swapchain->format.len; i++) {
 | 
			
		||||
			wlr_drm_format_set_add(&source->dmabuf_formats,
 | 
			
		||||
				swapchain->format.format, swapchain->format.modifiers[i]);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,111 +0,0 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <wlr/interfaces/wlr_ext_image_capture_source_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h>
 | 
			
		||||
#include "ext-image-capture-source-v1-protocol.h"
 | 
			
		||||
 | 
			
		||||
#define FOREIGN_TOPLEVEL_IMAGE_SOURCE_MANAGER_V1_VERSION 1
 | 
			
		||||
 | 
			
		||||
static const struct ext_foreign_toplevel_image_capture_source_manager_v1_interface foreign_toplevel_manager_impl;
 | 
			
		||||
 | 
			
		||||
static struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *
 | 
			
		||||
foreign_toplevel_manager_from_resource(struct wl_resource *resource) {
 | 
			
		||||
	assert(wl_resource_instance_of(resource,
 | 
			
		||||
		&ext_foreign_toplevel_image_capture_source_manager_v1_interface,
 | 
			
		||||
		&foreign_toplevel_manager_impl));
 | 
			
		||||
	return wl_resource_get_user_data(resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
	return wlr_ext_image_capture_source_v1_create_resource(source, request->client, request->new_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void foreign_toplevel_manager_handle_create_source(struct wl_client *client,
 | 
			
		||||
		struct wl_resource *manager_resource, uint32_t new_id,
 | 
			
		||||
		struct wl_resource *foreign_toplevel_resource) {
 | 
			
		||||
	struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *manager =
 | 
			
		||||
		foreign_toplevel_manager_from_resource(manager_resource);
 | 
			
		||||
	struct wlr_ext_foreign_toplevel_handle_v1 *toplevel_handle =
 | 
			
		||||
		wlr_ext_foreign_toplevel_handle_v1_from_resource(foreign_toplevel_resource);
 | 
			
		||||
	if (toplevel_handle == NULL) {
 | 
			
		||||
		wlr_ext_image_capture_source_v1_create_resource(NULL, client, new_id);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request *request =
 | 
			
		||||
		calloc(1, sizeof(*request));
 | 
			
		||||
	if (request == NULL) {
 | 
			
		||||
		wl_resource_post_no_memory(manager_resource);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	request->toplevel_handle = toplevel_handle;
 | 
			
		||||
	request->client = client;
 | 
			
		||||
	request->new_id = new_id;
 | 
			
		||||
 | 
			
		||||
	wl_signal_emit_mutable(&manager->events.new_request, request);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void foreign_toplevel_manager_handle_destroy(struct wl_client *client,
 | 
			
		||||
		struct wl_resource *manager_resource) {
 | 
			
		||||
	wl_resource_destroy(manager_resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct ext_foreign_toplevel_image_capture_source_manager_v1_interface foreign_toplevel_manager_impl = {
 | 
			
		||||
	.create_source = foreign_toplevel_manager_handle_create_source,
 | 
			
		||||
	.destroy = foreign_toplevel_manager_handle_destroy,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void foreign_toplevel_manager_bind(struct wl_client *client, void *data,
 | 
			
		||||
		uint32_t version, uint32_t id) {
 | 
			
		||||
	struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *manager = data;
 | 
			
		||||
 | 
			
		||||
	struct wl_resource *resource = wl_resource_create(client,
 | 
			
		||||
		&ext_foreign_toplevel_image_capture_source_manager_v1_interface, version, id);
 | 
			
		||||
	if (!resource) {
 | 
			
		||||
		wl_client_post_no_memory(client);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	wl_resource_set_implementation(resource, &foreign_toplevel_manager_impl, manager, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void foreign_toplevel_manager_handle_display_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *manager =
 | 
			
		||||
		wl_container_of(listener, manager, display_destroy);
 | 
			
		||||
	wl_signal_emit_mutable(&manager->events.destroy, NULL);
 | 
			
		||||
	assert(wl_list_empty(&manager->events.destroy.listener_list));
 | 
			
		||||
	assert(wl_list_empty(&manager->events.new_request.listener_list));
 | 
			
		||||
	wl_list_remove(&manager->display_destroy.link);
 | 
			
		||||
	wl_global_destroy(manager->global);
 | 
			
		||||
	free(manager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
	assert(version <= FOREIGN_TOPLEVEL_IMAGE_SOURCE_MANAGER_V1_VERSION);
 | 
			
		||||
 | 
			
		||||
	struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *manager =
 | 
			
		||||
		calloc(1, sizeof(*manager));
 | 
			
		||||
	if (manager == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	manager->global = wl_global_create(display,
 | 
			
		||||
		&ext_foreign_toplevel_image_capture_source_manager_v1_interface,
 | 
			
		||||
		version, manager, foreign_toplevel_manager_bind);
 | 
			
		||||
	if (manager->global == NULL) {
 | 
			
		||||
		free(manager);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_signal_init(&manager->events.destroy);
 | 
			
		||||
	wl_signal_init(&manager->events.new_request);
 | 
			
		||||
 | 
			
		||||
	manager->display_destroy.notify = foreign_toplevel_manager_handle_display_destroy;
 | 
			
		||||
	wl_display_add_destroy_listener(display, &manager->display_destroy);
 | 
			
		||||
 | 
			
		||||
	return manager;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -40,7 +40,7 @@ struct wlr_ext_output_image_capture_source_v1 {
 | 
			
		|||
struct wlr_ext_output_image_capture_source_v1_frame_event {
 | 
			
		||||
	struct wlr_ext_image_capture_source_v1_frame_event base;
 | 
			
		||||
	struct wlr_buffer *buffer;
 | 
			
		||||
	struct timespec when;
 | 
			
		||||
	struct timespec *when;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void output_source_start(struct wlr_ext_image_capture_source_v1 *base,
 | 
			
		||||
| 
						 | 
				
			
			@ -85,7 +85,7 @@ static void output_source_copy_frame(struct wlr_ext_image_capture_source_v1 *bas
 | 
			
		|||
	if (wlr_ext_image_copy_capture_frame_v1_copy_buffer(frame,
 | 
			
		||||
			event->buffer, source->output->renderer)) {
 | 
			
		||||
		wlr_ext_image_copy_capture_frame_v1_ready(frame,
 | 
			
		||||
			source->output->transform, &event->when);
 | 
			
		||||
			source->output->transform, event->when);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -283,8 +283,7 @@ static void output_cursor_source_copy_frame(struct wlr_ext_image_capture_source_
 | 
			
		|||
	struct timespec now;
 | 
			
		||||
	clock_gettime(CLOCK_MONOTONIC, &now);
 | 
			
		||||
 | 
			
		||||
	wlr_ext_image_copy_capture_frame_v1_ready(frame,
 | 
			
		||||
			cursor_source->output->transform, &now);
 | 
			
		||||
	wlr_ext_image_copy_capture_frame_v1_ready(frame, WL_OUTPUT_TRANSFORM_NORMAL, &now);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wlr_ext_image_capture_source_v1_interface output_cursor_source_impl = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,325 +0,0 @@
 | 
			
		|||
#include <limits.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <wlr/backend/interface.h>
 | 
			
		||||
#include <wlr/interfaces/wlr_ext_image_capture_source_v1.h>
 | 
			
		||||
#include <wlr/interfaces/wlr_output.h>
 | 
			
		||||
#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
 | 
			
		||||
#include "types/wlr_output.h"
 | 
			
		||||
#include "types/wlr_scene.h"
 | 
			
		||||
 | 
			
		||||
struct scene_node_source {
 | 
			
		||||
	struct wlr_ext_image_capture_source_v1 base;
 | 
			
		||||
 | 
			
		||||
	struct wlr_scene_node *node;
 | 
			
		||||
 | 
			
		||||
	struct wlr_backend backend;
 | 
			
		||||
	struct wlr_output output;
 | 
			
		||||
	struct wlr_scene_output *scene_output;
 | 
			
		||||
 | 
			
		||||
	struct wl_event_source *idle_frame;
 | 
			
		||||
 | 
			
		||||
	struct wl_listener node_destroy;
 | 
			
		||||
	struct wl_listener scene_output_destroy;
 | 
			
		||||
	struct wl_listener output_frame;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct scene_node_source_frame_event {
 | 
			
		||||
	struct wlr_ext_image_capture_source_v1_frame_event base;
 | 
			
		||||
	struct wlr_buffer *buffer;
 | 
			
		||||
	struct timespec when;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static size_t last_output_num = 0;
 | 
			
		||||
 | 
			
		||||
static void _get_scene_node_extents(struct wlr_scene_node *node, struct wlr_box *box, int lx, int ly) {
 | 
			
		||||
	switch (node->type) {
 | 
			
		||||
	case WLR_SCENE_NODE_TREE:;
 | 
			
		||||
		struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
 | 
			
		||||
		struct wlr_scene_node *child;
 | 
			
		||||
		wl_list_for_each(child, &scene_tree->children, link) {
 | 
			
		||||
			_get_scene_node_extents(child, box, lx + child->x, ly + child->y);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case WLR_SCENE_NODE_RECT:
 | 
			
		||||
	case WLR_SCENE_NODE_BUFFER:;
 | 
			
		||||
		struct wlr_box node_box = { .x = lx, .y = ly };
 | 
			
		||||
		scene_node_get_size(node, &node_box.width, &node_box.height);
 | 
			
		||||
 | 
			
		||||
		if (node_box.x < box->x) {
 | 
			
		||||
			box->x = node_box.x;
 | 
			
		||||
		}
 | 
			
		||||
		if (node_box.y < box->y) {
 | 
			
		||||
			box->y = node_box.y;
 | 
			
		||||
		}
 | 
			
		||||
		if (node_box.x + node_box.width > box->x + box->width) {
 | 
			
		||||
			box->width = node_box.x + node_box.width - box->x;
 | 
			
		||||
		}
 | 
			
		||||
		if (node_box.y + node_box.height > box->y + box->height) {
 | 
			
		||||
			box->height = node_box.y + node_box.height - box->y;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void get_scene_node_extents(struct wlr_scene_node *node, struct wlr_box *box) {
 | 
			
		||||
	*box = (struct wlr_box){ .x = INT_MAX, .y = INT_MAX };
 | 
			
		||||
	int lx = 0, ly = 0;
 | 
			
		||||
	wlr_scene_node_coords(node, &lx, &ly);
 | 
			
		||||
	_get_scene_node_extents(node, box, lx, ly);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void source_render(struct scene_node_source *source) {
 | 
			
		||||
	struct wlr_scene_output *scene_output = source->scene_output;
 | 
			
		||||
 | 
			
		||||
	struct wlr_box extents;
 | 
			
		||||
	get_scene_node_extents(source->node, &extents);
 | 
			
		||||
 | 
			
		||||
	if (extents.width == 0 || extents.height == 0) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_scene_output_set_position(scene_output, extents.x, extents.y);
 | 
			
		||||
 | 
			
		||||
	struct wlr_output_state state;
 | 
			
		||||
	wlr_output_state_init(&state);
 | 
			
		||||
	wlr_output_state_set_enabled(&state, true);
 | 
			
		||||
	wlr_output_state_set_custom_mode(&state, extents.width, extents.height, 0);
 | 
			
		||||
	bool ok = wlr_scene_output_build_state(scene_output, &state, NULL) &&
 | 
			
		||||
		wlr_output_commit_state(scene_output->output, &state);
 | 
			
		||||
	wlr_output_state_finish(&state);
 | 
			
		||||
 | 
			
		||||
	if (!ok) {
 | 
			
		||||
		// TODO: send failure
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct timespec now;
 | 
			
		||||
	clock_gettime(CLOCK_MONOTONIC, &now);
 | 
			
		||||
	wlr_scene_output_send_frame_done(scene_output, &now);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void source_start(struct wlr_ext_image_capture_source_v1 *base, bool with_cursors) {
 | 
			
		||||
	struct scene_node_source *source = wl_container_of(base, source, base);
 | 
			
		||||
	source_render(source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void source_stop(struct wlr_ext_image_capture_source_v1 *base) {
 | 
			
		||||
	struct scene_node_source *source = wl_container_of(base, source, base);
 | 
			
		||||
 | 
			
		||||
	struct wlr_output_state state;
 | 
			
		||||
	wlr_output_state_init(&state);
 | 
			
		||||
	wlr_output_state_set_enabled(&state, false);
 | 
			
		||||
	wlr_output_commit_state(&source->output, &state);
 | 
			
		||||
	wlr_output_state_finish(&state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void source_schedule_frame(struct wlr_ext_image_capture_source_v1 *base) {
 | 
			
		||||
	struct scene_node_source *source = wl_container_of(base, source, base);
 | 
			
		||||
	wlr_output_update_needs_frame(&source->output);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void source_copy_frame(struct wlr_ext_image_capture_source_v1 *base,
 | 
			
		||||
		struct wlr_ext_image_copy_capture_frame_v1 *frame,
 | 
			
		||||
		struct wlr_ext_image_capture_source_v1_frame_event *base_event) {
 | 
			
		||||
	struct scene_node_source *source = wl_container_of(base, source, base);
 | 
			
		||||
	struct scene_node_source_frame_event *event = wl_container_of(base_event, event, base);
 | 
			
		||||
 | 
			
		||||
	if (wlr_ext_image_copy_capture_frame_v1_copy_buffer(frame,
 | 
			
		||||
			event->buffer, source->output.renderer)) {
 | 
			
		||||
		wlr_ext_image_copy_capture_frame_v1_ready(frame,
 | 
			
		||||
			source->output.transform, &event->when);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wlr_ext_image_capture_source_v1_interface source_impl = {
 | 
			
		||||
	.start = source_start,
 | 
			
		||||
	.stop = source_stop,
 | 
			
		||||
	.schedule_frame = source_schedule_frame,
 | 
			
		||||
	.copy_frame = source_copy_frame,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct wlr_backend_impl backend_impl = {0};
 | 
			
		||||
 | 
			
		||||
static void source_update_buffer_constraints(struct scene_node_source *source,
 | 
			
		||||
		const struct wlr_output_state *state) {
 | 
			
		||||
	struct wlr_output *output = &source->output;
 | 
			
		||||
 | 
			
		||||
	if (!wlr_output_configure_primary_swapchain(output, state, &output->swapchain)) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_ext_image_capture_source_v1_set_constraints_from_swapchain(&source->base,
 | 
			
		||||
		output->swapchain, output->renderer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void source_handle_idle_frame(void *data) {
 | 
			
		||||
	struct scene_node_source *source = data;
 | 
			
		||||
	source->idle_frame = NULL;
 | 
			
		||||
	wlr_output_send_frame(&source->output);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool output_test(struct wlr_output *output, const struct wlr_output_state *state) {
 | 
			
		||||
	struct scene_node_source *source = wl_container_of(output, source, output);
 | 
			
		||||
 | 
			
		||||
	uint32_t supported =
 | 
			
		||||
		WLR_OUTPUT_STATE_BACKEND_OPTIONAL |
 | 
			
		||||
		WLR_OUTPUT_STATE_BUFFER |
 | 
			
		||||
		WLR_OUTPUT_STATE_ENABLED |
 | 
			
		||||
		WLR_OUTPUT_STATE_MODE;
 | 
			
		||||
	if ((state->committed & ~supported) != 0) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
 | 
			
		||||
		int pending_width, pending_height;
 | 
			
		||||
		output_pending_resolution(output, state,
 | 
			
		||||
			&pending_width, &pending_height);
 | 
			
		||||
		if (state->buffer->width != pending_width ||
 | 
			
		||||
				state->buffer->height != pending_height) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		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) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool output_commit(struct wlr_output *output, const struct wlr_output_state *state) {
 | 
			
		||||
	struct scene_node_source *source = wl_container_of(output, source, output);
 | 
			
		||||
 | 
			
		||||
	if (source->idle_frame != NULL) {
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Failed to commit capture output: a frame is still pending");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && !state->enabled) {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (state->committed & WLR_OUTPUT_STATE_MODE) {
 | 
			
		||||
		source_update_buffer_constraints(source, state);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(state->committed & WLR_OUTPUT_STATE_BUFFER)) {
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Failed to commit capture output: missing buffer");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_buffer *buffer = state->buffer;
 | 
			
		||||
 | 
			
		||||
	pixman_region32_t full_damage;
 | 
			
		||||
	pixman_region32_init_rect(&full_damage, 0, 0, buffer->width, buffer->height);
 | 
			
		||||
 | 
			
		||||
	const pixman_region32_t *damage;
 | 
			
		||||
	if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
 | 
			
		||||
		damage = &state->damage;
 | 
			
		||||
	} else {
 | 
			
		||||
		damage = &full_damage;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct timespec now;
 | 
			
		||||
	clock_gettime(CLOCK_MONOTONIC, &now);
 | 
			
		||||
 | 
			
		||||
	struct scene_node_source_frame_event frame_event = {
 | 
			
		||||
		.base = { .damage = damage },
 | 
			
		||||
		.buffer = buffer,
 | 
			
		||||
		.when = now,
 | 
			
		||||
	};
 | 
			
		||||
	wl_signal_emit_mutable(&source->base.events.frame, &frame_event.base);
 | 
			
		||||
 | 
			
		||||
	pixman_region32_fini(&full_damage);
 | 
			
		||||
 | 
			
		||||
	source->idle_frame =
 | 
			
		||||
		wl_event_loop_add_idle(output->event_loop, source_handle_idle_frame, source);
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wlr_output_impl output_impl = {
 | 
			
		||||
	.test = output_test,
 | 
			
		||||
	.commit = output_commit,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void source_destroy(struct scene_node_source *source) {
 | 
			
		||||
	wl_list_remove(&source->node_destroy.link);
 | 
			
		||||
	wl_list_remove(&source->scene_output_destroy.link);
 | 
			
		||||
	wl_list_remove(&source->output_frame.link);
 | 
			
		||||
	wlr_ext_image_capture_source_v1_finish(&source->base);
 | 
			
		||||
	wlr_scene_output_destroy(source->scene_output);
 | 
			
		||||
	wlr_output_finish(&source->output);
 | 
			
		||||
	wlr_backend_finish(&source->backend);
 | 
			
		||||
	free(source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void source_handle_node_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct scene_node_source *source = wl_container_of(listener, source, node_destroy);
 | 
			
		||||
	source_destroy(source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void source_handle_scene_output_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct scene_node_source *source = wl_container_of(listener, source, scene_output_destroy);
 | 
			
		||||
	source->scene_output = NULL;
 | 
			
		||||
	wl_list_remove(&source->scene_output_destroy.link);
 | 
			
		||||
	wl_list_init(&source->scene_output_destroy.link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void source_handle_output_frame(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct scene_node_source *source = wl_container_of(listener, source, output_frame);
 | 
			
		||||
	if (source->scene_output == NULL) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!wlr_scene_output_needs_frame(source->scene_output)) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	source_render(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) {
 | 
			
		||||
	struct scene_node_source *source = calloc(1, sizeof(*source));
 | 
			
		||||
	if (source == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	source->node = node;
 | 
			
		||||
 | 
			
		||||
	wlr_ext_image_capture_source_v1_init(&source->base, &source_impl);
 | 
			
		||||
 | 
			
		||||
	wlr_backend_init(&source->backend, &backend_impl);
 | 
			
		||||
	source->backend.buffer_caps = WLR_BUFFER_CAP_DMABUF | WLR_BUFFER_CAP_SHM;
 | 
			
		||||
 | 
			
		||||
	wlr_output_init(&source->output, &source->backend, &output_impl, event_loop, NULL);
 | 
			
		||||
 | 
			
		||||
	size_t output_num = ++last_output_num;
 | 
			
		||||
	char name[64];
 | 
			
		||||
	snprintf(name, sizeof(name), "CAPTURE-%zu", output_num);
 | 
			
		||||
	wlr_output_set_name(&source->output, name);
 | 
			
		||||
 | 
			
		||||
	wlr_output_init_render(&source->output, allocator, renderer);
 | 
			
		||||
 | 
			
		||||
	struct wlr_scene *scene = scene_node_get_root(node);
 | 
			
		||||
	source->scene_output = wlr_scene_output_create(scene, &source->output);
 | 
			
		||||
 | 
			
		||||
	source->node_destroy.notify = source_handle_node_destroy;
 | 
			
		||||
	wl_signal_add(&node->events.destroy, &source->node_destroy);
 | 
			
		||||
 | 
			
		||||
	source->scene_output_destroy.notify = source_handle_scene_output_destroy;
 | 
			
		||||
	wl_signal_add(&source->scene_output->events.destroy, &source->scene_output_destroy);
 | 
			
		||||
 | 
			
		||||
	source->output_frame.notify = source_handle_output_frame;
 | 
			
		||||
	wl_signal_add(&source->output.events.frame, &source->output_frame);
 | 
			
		||||
 | 
			
		||||
	return &source->base;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -5,8 +5,6 @@ wlr_files += files(
 | 
			
		|||
	'data_device/wlr_drag.c',
 | 
			
		||||
	'ext_image_capture_source_v1/base.c',
 | 
			
		||||
	'ext_image_capture_source_v1/output.c',
 | 
			
		||||
	'ext_image_capture_source_v1/foreign_toplevel.c',
 | 
			
		||||
	'ext_image_capture_source_v1/scene.c',
 | 
			
		||||
	'output/cursor.c',
 | 
			
		||||
	'output/output.c',
 | 
			
		||||
	'output/render.c',
 | 
			
		||||
| 
						 | 
				
			
			@ -39,20 +37,18 @@ wlr_files += files(
 | 
			
		|||
	'buffer/resource.c',
 | 
			
		||||
	'wlr_alpha_modifier_v1.c',
 | 
			
		||||
	'wlr_color_management_v1.c',
 | 
			
		||||
	'wlr_color_representation_v1.c',
 | 
			
		||||
	'wlr_compositor.c',
 | 
			
		||||
	'wlr_content_type_v1.c',
 | 
			
		||||
	'wlr_cursor.c',
 | 
			
		||||
	'wlr_cursor_shape_v1.c',
 | 
			
		||||
	'wlr_cursor.c',
 | 
			
		||||
	'wlr_damage_ring.c',
 | 
			
		||||
	'wlr_data_control_v1.c',
 | 
			
		||||
	'wlr_drm.c',
 | 
			
		||||
	'wlr_export_dmabuf_v1.c',
 | 
			
		||||
	'wlr_ext_data_control_v1.c',
 | 
			
		||||
	'wlr_ext_foreign_toplevel_list_v1.c',
 | 
			
		||||
	'wlr_ext_image_copy_capture_v1.c',
 | 
			
		||||
	'wlr_fixes.c',
 | 
			
		||||
	'wlr_foreign_toplevel_management_v1.c',
 | 
			
		||||
	'wlr_ext_image_copy_capture_v1.c',
 | 
			
		||||
	'wlr_ext_foreign_toplevel_list_v1.c',
 | 
			
		||||
	'wlr_ext_data_control_v1.c',
 | 
			
		||||
	'wlr_fractional_scale_v1.c',
 | 
			
		||||
	'wlr_gamma_control_v1.c',
 | 
			
		||||
	'wlr_idle_inhibit_v1.c',
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +101,6 @@ wlr_files += files(
 | 
			
		|||
	'wlr_xdg_output_v1.c',
 | 
			
		||||
	'wlr_xdg_system_bell_v1.c',
 | 
			
		||||
	'wlr_xdg_toplevel_icon_v1.c',
 | 
			
		||||
	'wlr_xdg_toplevel_tag_v1.c',
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
if features.get('drm-backend')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -288,10 +288,18 @@ static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor)
 | 
			
		|||
static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) {
 | 
			
		||||
	struct wlr_output *output = cursor->output;
 | 
			
		||||
 | 
			
		||||
	if (!output->impl->set_cursor || output->software_cursor_locks > 0) {
 | 
			
		||||
	if (!output->impl->set_cursor ||
 | 
			
		||||
			output->software_cursor_locks > 0) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_output_cursor *hwcur = output->hardware_cursor;
 | 
			
		||||
	if (hwcur != NULL && hwcur != cursor) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	output->hardware_cursor = NULL;
 | 
			
		||||
 | 
			
		||||
	struct wlr_texture *texture = cursor->texture;
 | 
			
		||||
 | 
			
		||||
	// If the cursor was hidden or was a software cursor, the hardware
 | 
			
		||||
| 
						 | 
				
			
			@ -416,15 +424,12 @@ bool output_cursor_set_texture(struct wlr_output_cursor *cursor,
 | 
			
		|||
		wl_list_init(&cursor->renderer_destroy.link);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (output->hardware_cursor == NULL || output->hardware_cursor == cursor) {
 | 
			
		||||
		if (output_cursor_attempt_hardware(cursor)) {
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Falling back to software cursor on output '%s'", output->name);
 | 
			
		||||
		output_disable_hardware_cursor(output);
 | 
			
		||||
	if (output_cursor_attempt_hardware(cursor)) {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Falling back to software cursor on output '%s'", output->name);
 | 
			
		||||
	output_disable_hardware_cursor(output);
 | 
			
		||||
	output_cursor_damage_whole(cursor);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,9 +16,20 @@
 | 
			
		|||
 | 
			
		||||
static void send_geometry(struct wl_resource *resource) {
 | 
			
		||||
	struct wlr_output *output = wlr_output_from_resource(resource);
 | 
			
		||||
 | 
			
		||||
	const char *make = output->make;
 | 
			
		||||
	if (make == NULL) {
 | 
			
		||||
		make = "Unknown";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const char *model = output->model;
 | 
			
		||||
	if (model == NULL) {
 | 
			
		||||
		model = "Unknown";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_output_send_geometry(resource, 0, 0,
 | 
			
		||||
		output->phys_width, output->phys_height, output->subpixel,
 | 
			
		||||
		"Unknown", "Unknown", output->transform);
 | 
			
		||||
		make, model, output->transform);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void send_current_mode(struct wl_resource *resource) {
 | 
			
		||||
| 
						 | 
				
			
			@ -233,24 +244,6 @@ static void output_apply_state(struct wlr_output *output,
 | 
			
		|||
		output->transform = state->transform;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
 | 
			
		||||
		if (state->image_description != NULL) {
 | 
			
		||||
			output->image_description_value = *state->image_description;
 | 
			
		||||
			output->image_description = &output->image_description_value;
 | 
			
		||||
		} else {
 | 
			
		||||
			output->image_description = NULL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
 | 
			
		||||
		wlr_color_transform_unref(output->color_transform);
 | 
			
		||||
		if (state->color_transform != NULL) {
 | 
			
		||||
			output->color_transform = wlr_color_transform_ref(state->color_transform);
 | 
			
		||||
		} else {
 | 
			
		||||
			output->color_transform = NULL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool geometry_updated = state->committed &
 | 
			
		||||
		(WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM |
 | 
			
		||||
		WLR_OUTPUT_STATE_SUBPIXEL);
 | 
			
		||||
| 
						 | 
				
			
			@ -416,7 +409,6 @@ void wlr_output_finish(struct wlr_output *output) {
 | 
			
		|||
 | 
			
		||||
	wlr_swapchain_destroy(output->cursor_swapchain);
 | 
			
		||||
	wlr_buffer_unlock(output->cursor_front_buffer);
 | 
			
		||||
	wlr_color_transform_unref(output->color_transform);
 | 
			
		||||
 | 
			
		||||
	wlr_swapchain_destroy(output->swapchain);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -510,14 +502,6 @@ bool output_pending_enabled(struct wlr_output *output,
 | 
			
		|||
	return output->enabled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct wlr_output_image_description *output_pending_image_description(
 | 
			
		||||
		struct wlr_output *output, const struct wlr_output_state *state) {
 | 
			
		||||
	if (state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
 | 
			
		||||
		return state->image_description;
 | 
			
		||||
	}
 | 
			
		||||
	return output->image_description;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Compare a struct wlr_output_state with the current state of a struct
 | 
			
		||||
 * wlr_output.
 | 
			
		||||
| 
						 | 
				
			
			@ -525,7 +509,8 @@ const struct wlr_output_image_description *output_pending_image_description(
 | 
			
		|||
 * Returns a bitfield of the unchanged fields.
 | 
			
		||||
 *
 | 
			
		||||
 * Some fields are not checked: damage always changes in-between frames, the
 | 
			
		||||
 * contents of the buffer might have changed, etc.
 | 
			
		||||
 * gamma LUT is too expensive to check, the contents of the buffer might have
 | 
			
		||||
 * changed, etc.
 | 
			
		||||
 */
 | 
			
		||||
static uint32_t output_compare_state(struct wlr_output *output,
 | 
			
		||||
		const struct wlr_output_state *state) {
 | 
			
		||||
| 
						 | 
				
			
			@ -571,10 +556,6 @@ static uint32_t output_compare_state(struct wlr_output *output,
 | 
			
		|||
			output->subpixel == state->subpixel) {
 | 
			
		||||
		fields |= WLR_OUTPUT_STATE_SUBPIXEL;
 | 
			
		||||
	}
 | 
			
		||||
	if ((state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) &&
 | 
			
		||||
			output->color_transform == state->color_transform) {
 | 
			
		||||
		fields |= WLR_OUTPUT_STATE_COLOR_TRANSFORM;
 | 
			
		||||
	}
 | 
			
		||||
	return fields;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -657,25 +638,29 @@ static bool output_basic_test(struct wlr_output *output,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const struct {
 | 
			
		||||
		enum wlr_output_state_field field;
 | 
			
		||||
		const char *name;
 | 
			
		||||
	} needs_enabled[] = {
 | 
			
		||||
		{ WLR_OUTPUT_STATE_BUFFER, "buffer" },
 | 
			
		||||
		{ WLR_OUTPUT_STATE_MODE, "mode" },
 | 
			
		||||
		{ WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED, "adaptive sync" },
 | 
			
		||||
		{ WLR_OUTPUT_STATE_RENDER_FORMAT, "render format" },
 | 
			
		||||
		{ WLR_OUTPUT_STATE_SUBPIXEL, "subpixel" },
 | 
			
		||||
		{ WLR_OUTPUT_STATE_COLOR_TRANSFORM, "color transform" },
 | 
			
		||||
		{ WLR_OUTPUT_STATE_IMAGE_DESCRIPTION, "image description" },
 | 
			
		||||
	};
 | 
			
		||||
	if (!enabled) {
 | 
			
		||||
		for (size_t i = 0; i < sizeof(needs_enabled) / sizeof(needs_enabled[0]); i++) {
 | 
			
		||||
			if (state->committed & needs_enabled[i].field) {
 | 
			
		||||
				wlr_log(WLR_DEBUG, "Tried to set %s on a disabled output", needs_enabled[i].name);
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	if (!enabled && state->committed & WLR_OUTPUT_STATE_BUFFER) {
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Tried to commit a buffer on a disabled output");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if (!enabled && state->committed & WLR_OUTPUT_STATE_MODE) {
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Tried to modeset a disabled output");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if (!enabled && state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) {
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Tried to enable adaptive sync on a disabled output");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if (!enabled && state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) {
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Tried to set format for a disabled output");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if (!enabled && state->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Tried to set the gamma lut on a disabled output");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if (!enabled && state->committed & WLR_OUTPUT_STATE_SUBPIXEL) {
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Tried to set the subpixel layout on a disabled output");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (state->committed & WLR_OUTPUT_STATE_LAYERS) {
 | 
			
		||||
| 
						 | 
				
			
			@ -695,18 +680,6 @@ static bool output_basic_test(struct wlr_output *output,
 | 
			
		|||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) &&
 | 
			
		||||
			state->image_description != NULL) {
 | 
			
		||||
		if (!(output->supported_primaries & state->image_description->primaries)) {
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Unsupported image description primaries");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		if (!(output->supported_transfer_functions & state->image_description->transfer_function)) {
 | 
			
		||||
			wlr_log(WLR_DEBUG, "Unsupported image description transfer function");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -755,7 +728,7 @@ bool output_prepare_commit(struct wlr_output *output, const struct wlr_output_st
 | 
			
		|||
 | 
			
		||||
	struct wlr_output_event_precommit pre_event = {
 | 
			
		||||
		.output = output,
 | 
			
		||||
		.when = now,
 | 
			
		||||
		.when = &now,
 | 
			
		||||
		.state = state,
 | 
			
		||||
	};
 | 
			
		||||
	wl_signal_emit_mutable(&output->events.precommit, &pre_event);
 | 
			
		||||
| 
						 | 
				
			
			@ -772,14 +745,12 @@ void output_apply_commit(struct wlr_output *output, const struct wlr_output_stat
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	output_apply_state(output, state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void output_send_commit_event(struct wlr_output *output, const struct wlr_output_state *state) {
 | 
			
		||||
	struct timespec now;
 | 
			
		||||
	clock_gettime(CLOCK_MONOTONIC, &now);
 | 
			
		||||
	struct wlr_output_event_commit event = {
 | 
			
		||||
		.output = output,
 | 
			
		||||
		.when = now,
 | 
			
		||||
		.when = &now,
 | 
			
		||||
		.state = state,
 | 
			
		||||
	};
 | 
			
		||||
	wl_signal_emit_mutable(&output->events.commit, &event);
 | 
			
		||||
| 
						 | 
				
			
			@ -816,7 +787,6 @@ bool wlr_output_commit_state(struct wlr_output *output,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	output_apply_commit(output, &pending);
 | 
			
		||||
	output_send_commit_event(output, &pending);
 | 
			
		||||
 | 
			
		||||
	if (new_back_buffer) {
 | 
			
		||||
		wlr_buffer_unlock(pending.buffer);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <wlr/render/drm_syncobj.h>
 | 
			
		||||
#include <wlr/render/color.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
#include "types/wlr_output.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -17,9 +16,9 @@ void wlr_output_state_finish(struct wlr_output_state *state) {
 | 
			
		|||
	// reads it after output_state_finish().
 | 
			
		||||
	state->buffer = NULL;
 | 
			
		||||
	pixman_region32_fini(&state->damage);
 | 
			
		||||
	free(state->gamma_lut);
 | 
			
		||||
	wlr_drm_syncobj_timeline_unref(state->wait_timeline);
 | 
			
		||||
	wlr_drm_syncobj_timeline_unref(state->signal_timeline);
 | 
			
		||||
	free(state->image_description);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wlr_output_state_set_enabled(struct wlr_output_state *state,
 | 
			
		||||
| 
						 | 
				
			
			@ -89,6 +88,28 @@ void wlr_output_state_set_damage(struct wlr_output_state *state,
 | 
			
		|||
	pixman_region32_copy(&state->damage, damage);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool wlr_output_state_set_gamma_lut(struct wlr_output_state *state,
 | 
			
		||||
		size_t ramp_size, const uint16_t *r, const uint16_t *g, const uint16_t *b) {
 | 
			
		||||
	uint16_t *gamma_lut = NULL;
 | 
			
		||||
	if (ramp_size > 0) {
 | 
			
		||||
		gamma_lut = realloc(state->gamma_lut, 3 * ramp_size * sizeof(uint16_t));
 | 
			
		||||
		if (gamma_lut == NULL) {
 | 
			
		||||
			wlr_log_errno(WLR_ERROR, "Allocation failed");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		memcpy(gamma_lut, r, ramp_size * sizeof(uint16_t));
 | 
			
		||||
		memcpy(gamma_lut + ramp_size, g, ramp_size * sizeof(uint16_t));
 | 
			
		||||
		memcpy(gamma_lut + 2 * ramp_size, b, ramp_size * sizeof(uint16_t));
 | 
			
		||||
	} else {
 | 
			
		||||
		free(state->gamma_lut);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	state->committed |= WLR_OUTPUT_STATE_GAMMA_LUT;
 | 
			
		||||
	state->gamma_lut_size = ramp_size;
 | 
			
		||||
	state->gamma_lut = gamma_lut;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wlr_output_state_set_layers(struct wlr_output_state *state,
 | 
			
		||||
		struct wlr_output_layer_state *layers, size_t layers_len) {
 | 
			
		||||
	state->committed |= WLR_OUTPUT_STATE_LAYERS;
 | 
			
		||||
| 
						 | 
				
			
			@ -112,51 +133,22 @@ void wlr_output_state_set_signal_timeline(struct wlr_output_state *state,
 | 
			
		|||
	state->signal_point = dst_point;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wlr_output_state_set_color_transform(struct wlr_output_state *state,
 | 
			
		||||
		struct wlr_color_transform *tr) {
 | 
			
		||||
	state->committed |= WLR_OUTPUT_STATE_COLOR_TRANSFORM;
 | 
			
		||||
	wlr_color_transform_unref(state->color_transform);
 | 
			
		||||
	if (tr) {
 | 
			
		||||
		state->color_transform = wlr_color_transform_ref(tr);
 | 
			
		||||
	} else {
 | 
			
		||||
		state->color_transform = NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool wlr_output_state_set_image_description(struct wlr_output_state *state,
 | 
			
		||||
		const struct wlr_output_image_description *image_desc) {
 | 
			
		||||
	struct wlr_output_image_description *copy = NULL;
 | 
			
		||||
	if (image_desc != NULL) {
 | 
			
		||||
		copy = malloc(sizeof(*copy));
 | 
			
		||||
		if (copy == NULL) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		*copy = *image_desc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	state->committed |= WLR_OUTPUT_STATE_IMAGE_DESCRIPTION;
 | 
			
		||||
	free(state->image_description);
 | 
			
		||||
	state->image_description = copy;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool wlr_output_state_copy(struct wlr_output_state *dst,
 | 
			
		||||
		const struct wlr_output_state *src) {
 | 
			
		||||
	struct wlr_output_state copy = *src;
 | 
			
		||||
	copy.committed &= ~(WLR_OUTPUT_STATE_BUFFER |
 | 
			
		||||
		WLR_OUTPUT_STATE_DAMAGE |
 | 
			
		||||
		WLR_OUTPUT_STATE_GAMMA_LUT |
 | 
			
		||||
		WLR_OUTPUT_STATE_WAIT_TIMELINE |
 | 
			
		||||
		WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
 | 
			
		||||
		WLR_OUTPUT_STATE_COLOR_TRANSFORM |
 | 
			
		||||
		WLR_OUTPUT_STATE_IMAGE_DESCRIPTION);
 | 
			
		||||
		WLR_OUTPUT_STATE_SIGNAL_TIMELINE);
 | 
			
		||||
	copy.buffer = NULL;
 | 
			
		||||
	copy.buffer_src_box = (struct wlr_fbox){0};
 | 
			
		||||
	copy.buffer_dst_box = (struct wlr_box){0};
 | 
			
		||||
	pixman_region32_init(©.damage);
 | 
			
		||||
	copy.gamma_lut = NULL;
 | 
			
		||||
	copy.gamma_lut_size = 0;
 | 
			
		||||
	copy.wait_timeline = NULL;
 | 
			
		||||
	copy.signal_timeline = NULL;
 | 
			
		||||
	copy.color_transform = NULL;
 | 
			
		||||
	copy.image_description = NULL;
 | 
			
		||||
 | 
			
		||||
	if (src->committed & WLR_OUTPUT_STATE_BUFFER) {
 | 
			
		||||
		wlr_output_state_set_buffer(©, src->buffer);
 | 
			
		||||
| 
						 | 
				
			
			@ -168,6 +160,15 @@ bool wlr_output_state_copy(struct wlr_output_state *dst,
 | 
			
		|||
		wlr_output_state_set_damage(©, &src->damage);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (src->committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
 | 
			
		||||
		const uint16_t *r = src->gamma_lut;
 | 
			
		||||
		const uint16_t *g = src->gamma_lut + src->gamma_lut_size;
 | 
			
		||||
		const uint16_t *b = src->gamma_lut + 2 * src->gamma_lut_size;
 | 
			
		||||
		if (!wlr_output_state_set_gamma_lut(©, src->gamma_lut_size, r, g, b)) {
 | 
			
		||||
			goto err;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (src->committed & WLR_OUTPUT_STATE_WAIT_TIMELINE) {
 | 
			
		||||
		wlr_output_state_set_wait_timeline(©, src->wait_timeline,
 | 
			
		||||
			src->wait_point);
 | 
			
		||||
| 
						 | 
				
			
			@ -177,20 +178,11 @@ bool wlr_output_state_copy(struct wlr_output_state *dst,
 | 
			
		|||
			src->signal_point);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (src->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
 | 
			
		||||
		wlr_output_state_set_color_transform(©, src->color_transform);
 | 
			
		||||
	}
 | 
			
		||||
	if (src->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
 | 
			
		||||
		if (!wlr_output_state_set_image_description(©, src->image_description)) {
 | 
			
		||||
			goto err;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_output_state_finish(dst);
 | 
			
		||||
	*dst = copy;
 | 
			
		||||
	return true;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
	wlr_output_state_finish(dst);
 | 
			
		||||
	wlr_output_state_finish(©);
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <wlr/types/wlr_alpha_modifier_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_color_management_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_compositor.h>
 | 
			
		||||
#include <wlr/types/wlr_scene.h>
 | 
			
		||||
#include <wlr/types/wlr_fractional_scale_v1.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -12,99 +11,19 @@
 | 
			
		|||
#include <wlr/util/transform.h>
 | 
			
		||||
#include "types/wlr_scene.h"
 | 
			
		||||
 | 
			
		||||
static double get_surface_preferred_buffer_scale(struct wlr_surface *surface) {
 | 
			
		||||
	double scale = 1;
 | 
			
		||||
	struct wlr_surface_output *surface_output;
 | 
			
		||||
	wl_list_for_each(surface_output, &surface->current_outputs, link) {
 | 
			
		||||
		if (surface_output->output->scale > scale) {
 | 
			
		||||
			scale = surface_output->output->scale;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return scale;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wlr_output *get_surface_frame_pacing_output(struct wlr_surface *surface) {
 | 
			
		||||
	struct wlr_output *frame_pacing_output = NULL;
 | 
			
		||||
	struct wlr_surface_output *surface_output;
 | 
			
		||||
	wl_list_for_each(surface_output, &surface->current_outputs, link) {
 | 
			
		||||
		if (frame_pacing_output == NULL ||
 | 
			
		||||
				surface_output->output->refresh > frame_pacing_output->refresh) {
 | 
			
		||||
			frame_pacing_output = surface_output->output;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return frame_pacing_output;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool get_tf_preference(enum wlr_color_transfer_function tf) {
 | 
			
		||||
	switch (tf) {
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
 | 
			
		||||
		return 0;
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
 | 
			
		||||
		return 1;
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	abort(); // unreachable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool get_primaries_preference(enum wlr_color_named_primaries primaries) {
 | 
			
		||||
	switch (primaries) {
 | 
			
		||||
	case WLR_COLOR_NAMED_PRIMARIES_SRGB:
 | 
			
		||||
		return 0;
 | 
			
		||||
	case WLR_COLOR_NAMED_PRIMARIES_BT2020:
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	abort(); // unreachable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void get_surface_preferred_image_description(struct wlr_surface *surface,
 | 
			
		||||
		struct wlr_image_description_v1_data *out) {
 | 
			
		||||
	struct wlr_output_image_description preferred = {
 | 
			
		||||
		.transfer_function = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22,
 | 
			
		||||
		.primaries = WLR_COLOR_NAMED_PRIMARIES_SRGB,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct wlr_surface_output *surface_output;
 | 
			
		||||
	wl_list_for_each(surface_output, &surface->current_outputs, link) {
 | 
			
		||||
		const struct wlr_output_image_description *img_desc =
 | 
			
		||||
			surface_output->output->image_description;
 | 
			
		||||
		if (img_desc == NULL) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		if (get_tf_preference(preferred.transfer_function) < get_tf_preference(img_desc->transfer_function)) {
 | 
			
		||||
			preferred.transfer_function = img_desc->transfer_function;
 | 
			
		||||
		}
 | 
			
		||||
		if (get_primaries_preference(preferred.primaries) < get_primaries_preference(img_desc->primaries)) {
 | 
			
		||||
			preferred.primaries = img_desc->primaries;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*out = (struct wlr_image_description_v1_data){
 | 
			
		||||
		.tf_named = wlr_color_manager_v1_transfer_function_from_wlr(preferred.transfer_function),
 | 
			
		||||
		.primaries_named = wlr_color_manager_v1_primaries_from_wlr(preferred.primaries),
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_scene_buffer_outputs_update(
 | 
			
		||||
		struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wlr_scene_surface *surface =
 | 
			
		||||
		wl_container_of(listener, surface, outputs_update);
 | 
			
		||||
	struct wlr_scene *scene = scene_node_get_root(&surface->buffer->node);
 | 
			
		||||
 | 
			
		||||
	surface->frame_pacing_output = get_surface_frame_pacing_output(surface->surface);
 | 
			
		||||
 | 
			
		||||
	double scale = get_surface_preferred_buffer_scale(surface->surface);
 | 
			
		||||
	if (surface->buffer->primary_output == NULL) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	double scale = surface->buffer->primary_output->output->scale;
 | 
			
		||||
	wlr_fractional_scale_v1_notify_scale(surface->surface, scale);
 | 
			
		||||
	wlr_surface_set_preferred_buffer_scale(surface->surface, ceil(scale));
 | 
			
		||||
 | 
			
		||||
	if (scene->color_manager_v1 != NULL) {
 | 
			
		||||
		struct wlr_image_description_v1_data img_desc = {0};
 | 
			
		||||
		get_surface_preferred_image_description(surface->surface, &img_desc);
 | 
			
		||||
		wlr_color_manager_v1_set_surface_preferred_image_description(scene->color_manager_v1,
 | 
			
		||||
			surface->surface, &img_desc);
 | 
			
		||||
	}
 | 
			
		||||
	wlr_surface_set_preferred_buffer_transform(surface->surface,
 | 
			
		||||
		surface->buffer->primary_output->output->transform);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_scene_buffer_output_enter(
 | 
			
		||||
| 
						 | 
				
			
			@ -130,15 +49,15 @@ static void handle_scene_buffer_output_sample(
 | 
			
		|||
	struct wlr_scene_surface *surface =
 | 
			
		||||
		wl_container_of(listener, surface, output_sample);
 | 
			
		||||
	const struct wlr_scene_output_sample_event *event = data;
 | 
			
		||||
	struct wlr_output *output = event->output->output;
 | 
			
		||||
	if (surface->frame_pacing_output != output) {
 | 
			
		||||
	struct wlr_scene_output *scene_output = event->output;
 | 
			
		||||
	if (surface->buffer->primary_output != scene_output) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (event->direct_scanout) {
 | 
			
		||||
		wlr_presentation_surface_scanned_out_on_output(surface->surface, output);
 | 
			
		||||
		wlr_presentation_surface_scanned_out_on_output(surface->surface, scene_output->output);
 | 
			
		||||
	} else {
 | 
			
		||||
		wlr_presentation_surface_textured_on_output(surface->surface, output);
 | 
			
		||||
		wlr_presentation_surface_textured_on_output(surface->surface, scene_output->output);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -146,19 +65,9 @@ static void handle_scene_buffer_frame_done(
 | 
			
		|||
		struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wlr_scene_surface *surface =
 | 
			
		||||
		wl_container_of(listener, surface, frame_done);
 | 
			
		||||
	struct wlr_scene_frame_done_event *event = data;
 | 
			
		||||
	if (surface->frame_pacing_output != event->output->output) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	struct timespec *now = data;
 | 
			
		||||
 | 
			
		||||
	wlr_surface_send_frame_done(surface->surface, &event->when);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wlr_scene_surface_send_frame_done(struct wlr_scene_surface *scene_surface,
 | 
			
		||||
		const struct timespec *when) {
 | 
			
		||||
	if (!pixman_region32_empty(&scene_surface->buffer->node.visible)) {
 | 
			
		||||
		wlr_surface_send_frame_done(scene_surface->surface, when);
 | 
			
		||||
	}
 | 
			
		||||
	wlr_surface_send_frame_done(surface->surface, now);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void scene_surface_handle_surface_destroy(
 | 
			
		||||
| 
						 | 
				
			
			@ -187,11 +96,8 @@ static void scene_buffer_unmark_client_buffer(struct wlr_scene_buffer *scene_buf
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the buffer was a single-pixel buffer where we cached its color
 | 
			
		||||
	// then it won't have been marked as damage-allowed.
 | 
			
		||||
	if (buffer->n_ignore_locks > 0) {
 | 
			
		||||
		buffer->n_ignore_locks--;
 | 
			
		||||
	}
 | 
			
		||||
	assert(buffer->n_ignore_locks > 0);
 | 
			
		||||
	buffer->n_ignore_locks--;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int min(int a, int b) {
 | 
			
		||||
| 
						 | 
				
			
			@ -250,41 +156,16 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
 | 
			
		|||
		opacity = (float)alpha_modifier_state->multiplier;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
 | 
			
		||||
	enum wlr_color_named_primaries primaries = WLR_COLOR_NAMED_PRIMARIES_SRGB;
 | 
			
		||||
	const struct wlr_image_description_v1_data *img_desc =
 | 
			
		||||
		wlr_surface_get_image_description_v1_data(surface);
 | 
			
		||||
	if (img_desc != NULL) {
 | 
			
		||||
		tf = wlr_color_manager_v1_transfer_function_to_wlr(img_desc->tf_named);
 | 
			
		||||
		primaries = wlr_color_manager_v1_primaries_to_wlr(img_desc->primaries_named);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_scene_buffer_set_opaque_region(scene_buffer, &opaque);
 | 
			
		||||
	wlr_scene_buffer_set_source_box(scene_buffer, &src_box);
 | 
			
		||||
	wlr_scene_buffer_set_dest_size(scene_buffer, width, height);
 | 
			
		||||
	wlr_scene_buffer_set_transform(scene_buffer, state->transform);
 | 
			
		||||
	wlr_scene_buffer_set_opacity(scene_buffer, opacity);
 | 
			
		||||
	wlr_scene_buffer_set_transfer_function(scene_buffer, tf);
 | 
			
		||||
	wlr_scene_buffer_set_primaries(scene_buffer, primaries);
 | 
			
		||||
 | 
			
		||||
	scene_buffer_unmark_client_buffer(scene_buffer);
 | 
			
		||||
 | 
			
		||||
	if (surface->buffer) {
 | 
			
		||||
		// If we've cached the buffer's single-pixel buffer color
 | 
			
		||||
		// then any in-place updates to the texture wouldn't be
 | 
			
		||||
		// reflected in rendering. So only allow in-place texture
 | 
			
		||||
		// updates if it's not a single pixel buffer.  Note that we
 | 
			
		||||
		// can't use the cached scene_buffer->is_single_pixel_buffer
 | 
			
		||||
		// because that's only set later on.
 | 
			
		||||
		bool is_single_pixel_buffer = false;
 | 
			
		||||
		if (surface->buffer->source != NULL) {
 | 
			
		||||
			struct wlr_single_pixel_buffer_v1 *spb =
 | 
			
		||||
				wlr_single_pixel_buffer_v1_try_from_buffer(surface->buffer->source);
 | 
			
		||||
			is_single_pixel_buffer = spb != NULL;
 | 
			
		||||
		}
 | 
			
		||||
		if (!is_single_pixel_buffer) {
 | 
			
		||||
			client_buffer_mark_next_can_damage(surface->buffer);
 | 
			
		||||
		}
 | 
			
		||||
		client_buffer_mark_next_can_damage(surface->buffer);
 | 
			
		||||
 | 
			
		||||
		struct wlr_linux_drm_syncobj_surface_v1_state *syncobj_surface_state =
 | 
			
		||||
			wlr_linux_drm_syncobj_v1_get_surface_state(surface);
 | 
			
		||||
| 
						 | 
				
			
			@ -305,8 +186,7 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
 | 
			
		|||
			&surface->buffer->base, &options);
 | 
			
		||||
 | 
			
		||||
		if (syncobj_surface_state != NULL &&
 | 
			
		||||
				(surface->current.committed & WLR_SURFACE_STATE_BUFFER) &&
 | 
			
		||||
				surface->buffer->source != NULL) {
 | 
			
		||||
				(surface->current.committed & WLR_SURFACE_STATE_BUFFER)) {
 | 
			
		||||
			wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(syncobj_surface_state,
 | 
			
		||||
				surface->buffer->source);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,6 @@
 | 
			
		|||
#include <wlr/render/swapchain.h>
 | 
			
		||||
#include <wlr/render/drm_syncobj.h>
 | 
			
		||||
#include <wlr/render/wlr_renderer.h>
 | 
			
		||||
#include <wlr/types/wlr_color_management_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_compositor.h>
 | 
			
		||||
#include <wlr/types/wlr_damage_ring.h>
 | 
			
		||||
#include <wlr/types/wlr_gamma_control_v1.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +14,6 @@
 | 
			
		|||
#include <wlr/util/log.h>
 | 
			
		||||
#include <wlr/util/region.h>
 | 
			
		||||
#include <wlr/util/transform.h>
 | 
			
		||||
#include "render/color.h"
 | 
			
		||||
#include "types/wlr_output.h"
 | 
			
		||||
#include "types/wlr_scene.h"
 | 
			
		||||
#include "util/array.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -212,6 +210,8 @@ struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent) {
 | 
			
		|||
	return tree;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void scene_node_get_size(struct wlr_scene_node *node, int *lx, int *ly);
 | 
			
		||||
 | 
			
		||||
typedef bool (*scene_node_box_iterator_func_t)(struct wlr_scene_node *node,
 | 
			
		||||
	int sx, int sy, void *data);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -426,8 +426,6 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
 | 
			
		|||
	size_t count = 0;
 | 
			
		||||
	uint64_t active_outputs = 0;
 | 
			
		||||
 | 
			
		||||
	uint32_t visible_area = region_area(&node->visible);
 | 
			
		||||
 | 
			
		||||
	// let's update the outputs in two steps:
 | 
			
		||||
	//  - the primary outputs
 | 
			
		||||
	//  - the enter/leave signals
 | 
			
		||||
| 
						 | 
				
			
			@ -455,12 +453,9 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
 | 
			
		|||
		pixman_region32_init(&intersection);
 | 
			
		||||
		pixman_region32_intersect_rect(&intersection, &node->visible,
 | 
			
		||||
			output_box.x, output_box.y, output_box.width, output_box.height);
 | 
			
		||||
		uint32_t overlap = region_area(&intersection);
 | 
			
		||||
		pixman_region32_fini(&intersection);
 | 
			
		||||
 | 
			
		||||
		// If the overlap accounts for less than 10% of the visible node area,
 | 
			
		||||
		// ignore this output
 | 
			
		||||
		if (overlap >= 0.1 * visible_area) {
 | 
			
		||||
		if (!pixman_region32_empty(&intersection)) {
 | 
			
		||||
			uint32_t overlap = region_area(&intersection);
 | 
			
		||||
			if (overlap >= largest_overlap) {
 | 
			
		||||
				largest_overlap = overlap;
 | 
			
		||||
				scene_buffer->primary_output = scene_output;
 | 
			
		||||
| 
						 | 
				
			
			@ -469,6 +464,8 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
 | 
			
		|||
			active_outputs |= 1ull << scene_output->index;
 | 
			
		||||
			count++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pixman_region32_fini(&intersection);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (old_primary_output != scene_buffer->primary_output) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1074,9 +1071,9 @@ void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer,
 | 
			
		||||
		struct wlr_scene_frame_done_event *event) {
 | 
			
		||||
		struct timespec *now) {
 | 
			
		||||
	if (!pixman_region32_empty(&scene_buffer->node.visible)) {
 | 
			
		||||
		wl_signal_emit_mutable(&scene_buffer->events.frame_done, event);
 | 
			
		||||
		wl_signal_emit_mutable(&scene_buffer->events.frame_done, now);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1101,26 +1098,6 @@ void wlr_scene_buffer_set_filter_mode(struct wlr_scene_buffer *scene_buffer,
 | 
			
		|||
	scene_node_update(&scene_buffer->node, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wlr_scene_buffer_set_transfer_function(struct wlr_scene_buffer *scene_buffer,
 | 
			
		||||
		enum wlr_color_transfer_function transfer_function) {
 | 
			
		||||
	if (scene_buffer->transfer_function == transfer_function) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scene_buffer->transfer_function = transfer_function;
 | 
			
		||||
	scene_node_update(&scene_buffer->node, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wlr_scene_buffer_set_primaries(struct wlr_scene_buffer *scene_buffer,
 | 
			
		||||
		enum wlr_color_named_primaries primaries) {
 | 
			
		||||
	if (scene_buffer->primaries == primaries) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scene_buffer->primaries = primaries;
 | 
			
		||||
	scene_node_update(&scene_buffer->node, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wlr_texture *scene_buffer_get_texture(
 | 
			
		||||
		struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) {
 | 
			
		||||
	if (scene_buffer->buffer == NULL || scene_buffer->texture != NULL) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1143,7 +1120,8 @@ static struct wlr_texture *scene_buffer_get_texture(
 | 
			
		|||
	return texture;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void scene_node_get_size(struct wlr_scene_node *node, int *width, int *height) {
 | 
			
		||||
static void scene_node_get_size(struct wlr_scene_node *node,
 | 
			
		||||
		int *width, int *height) {
 | 
			
		||||
	*width = 0;
 | 
			
		||||
	*height = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1457,11 +1435,6 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
 | 
			
		|||
			wlr_output_transform_invert(scene_buffer->transform);
 | 
			
		||||
		transform = wlr_output_transform_compose(transform, data->transform);
 | 
			
		||||
 | 
			
		||||
		struct wlr_color_primaries primaries = {0};
 | 
			
		||||
		if (scene_buffer->primaries != 0) {
 | 
			
		||||
			wlr_color_primaries_from_named(&primaries, scene_buffer->primaries);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		wlr_render_pass_add_texture(data->render_pass, &(struct wlr_render_texture_options) {
 | 
			
		||||
			.texture = texture,
 | 
			
		||||
			.src_box = scene_buffer->src_box,
 | 
			
		||||
| 
						 | 
				
			
			@ -1473,8 +1446,6 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
 | 
			
		|||
			.blend_mode = !data->output->scene->calculate_visibility ||
 | 
			
		||||
					!pixman_region32_empty(&opaque) ?
 | 
			
		||||
				WLR_RENDER_BLEND_MODE_PREMULTIPLIED : WLR_RENDER_BLEND_MODE_NONE,
 | 
			
		||||
			.transfer_function = scene_buffer->transfer_function,
 | 
			
		||||
			.primaries = scene_buffer->primaries != 0 ? &primaries : NULL,
 | 
			
		||||
			.wait_timeline = scene_buffer->wait_timeline,
 | 
			
		||||
			.wait_point = scene_buffer->wait_point,
 | 
			
		||||
		});
 | 
			
		||||
| 
						 | 
				
			
			@ -1530,8 +1501,6 @@ static void scene_handle_gamma_control_manager_v1_set_gamma(struct wl_listener *
 | 
			
		|||
 | 
			
		||||
	output->gamma_lut_changed = true;
 | 
			
		||||
	output->gamma_lut = event->control;
 | 
			
		||||
	wlr_color_transform_unref(output->gamma_lut_color_transform);
 | 
			
		||||
	output->gamma_lut_color_transform = wlr_gamma_control_v1_get_color_transform(event->control);
 | 
			
		||||
	wlr_output_schedule_frame(output->output);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1549,8 +1518,6 @@ static void scene_handle_gamma_control_manager_v1_destroy(struct wl_listener *li
 | 
			
		|||
	wl_list_for_each(output, &scene->outputs, link) {
 | 
			
		||||
		output->gamma_lut_changed = false;
 | 
			
		||||
		output->gamma_lut = NULL;
 | 
			
		||||
		wlr_color_transform_unref(output->gamma_lut_color_transform);
 | 
			
		||||
		output->gamma_lut_color_transform = NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1567,21 +1534,6 @@ void wlr_scene_set_gamma_control_manager_v1(struct wlr_scene *scene,
 | 
			
		|||
	wl_signal_add(&gamma_control->events.set_gamma, &scene->gamma_control_manager_v1_set_gamma);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void scene_handle_color_manager_v1_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wlr_scene *scene = wl_container_of(listener, scene, color_manager_v1_destroy);
 | 
			
		||||
	wl_list_remove(&scene->color_manager_v1_destroy.link);
 | 
			
		||||
	wl_list_init(&scene->color_manager_v1_destroy.link);
 | 
			
		||||
	scene->color_manager_v1 = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wlr_scene_set_color_manager_v1(struct wlr_scene *scene, struct wlr_color_manager_v1 *manager) {
 | 
			
		||||
	assert(scene->color_manager_v1 == NULL);
 | 
			
		||||
	scene->color_manager_v1 = manager;
 | 
			
		||||
 | 
			
		||||
	scene->color_manager_v1_destroy.notify = scene_handle_color_manager_v1_destroy;
 | 
			
		||||
	wl_signal_add(&manager->events.destroy, &scene->color_manager_v1_destroy);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void scene_output_handle_destroy(struct wlr_addon *addon) {
 | 
			
		||||
	struct wlr_scene_output *scene_output =
 | 
			
		||||
		wl_container_of(addon, scene_output, addon);
 | 
			
		||||
| 
						 | 
				
			
			@ -1770,10 +1722,6 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) {
 | 
			
		|||
	wl_list_remove(&scene_output->output_damage.link);
 | 
			
		||||
	wl_list_remove(&scene_output->output_needs_frame.link);
 | 
			
		||||
	wlr_drm_syncobj_timeline_unref(scene_output->in_timeline);
 | 
			
		||||
	wlr_color_transform_unref(scene_output->gamma_lut_color_transform);
 | 
			
		||||
	wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform);
 | 
			
		||||
	wlr_color_transform_unref(scene_output->prev_supplied_color_transform);
 | 
			
		||||
	wlr_color_transform_unref(scene_output->prev_combined_color_transform);
 | 
			
		||||
	wl_array_release(&scene_output->render_list);
 | 
			
		||||
	free(scene_output);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1919,41 +1867,12 @@ static void scene_buffer_send_dmabuf_feedback(const struct wlr_scene *scene,
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	enum wl_output_transform preferred_buffer_transform = WL_OUTPUT_TRANSFORM_NORMAL;
 | 
			
		||||
	if (options->scanout_primary_output != NULL) {
 | 
			
		||||
		preferred_buffer_transform = options->scanout_primary_output->transform;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: also send wl_surface.preferred_buffer_transform when running with
 | 
			
		||||
	// pure software rendering
 | 
			
		||||
	wlr_surface_set_preferred_buffer_transform(surface->surface, preferred_buffer_transform);
 | 
			
		||||
	wlr_linux_dmabuf_v1_set_surface_feedback(scene->linux_dmabuf_v1,
 | 
			
		||||
		surface->surface, &feedback);
 | 
			
		||||
 | 
			
		||||
	wlr_linux_dmabuf_feedback_v1_finish(&feedback);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool color_management_is_scanout_allowed(const struct wlr_output_image_description *img_desc,
 | 
			
		||||
		const struct wlr_scene_buffer *buffer) {
 | 
			
		||||
	// Disallow scanout if the output has colorimetry information but buffer
 | 
			
		||||
	// doesn't; allow it only if the output also lacks it.
 | 
			
		||||
	if (buffer->transfer_function == 0 && buffer->primaries == 0) {
 | 
			
		||||
		return img_desc == NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the output has colorimetry information, the buffer must match it for
 | 
			
		||||
	// direct scanout to be allowed.
 | 
			
		||||
	if (img_desc != NULL) {
 | 
			
		||||
		return img_desc->transfer_function == buffer->transfer_function &&
 | 
			
		||||
				img_desc->primaries == buffer->primaries;
 | 
			
		||||
	}
 | 
			
		||||
	// If the output doesn't have colorimetry image description set, we can only
 | 
			
		||||
	// scan out buffers with default colorimetry (gamma2.2 transfer and sRGB
 | 
			
		||||
	// primaries) used in wlroots.
 | 
			
		||||
	return buffer->transfer_function == WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 &&
 | 
			
		||||
			buffer->primaries == WLR_COLOR_NAMED_PRIMARIES_SRGB;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum scene_direct_scanout_result {
 | 
			
		||||
	// This scene node is not a candidate for scanout
 | 
			
		||||
	SCANOUT_INELIGIBLE,
 | 
			
		||||
| 
						 | 
				
			
			@ -2010,11 +1929,6 @@ static enum scene_direct_scanout_result scene_entry_try_direct_scanout(
 | 
			
		|||
		return SCANOUT_INELIGIBLE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const struct wlr_output_image_description *img_desc = output_pending_image_description(scene_output->output, state);
 | 
			
		||||
	if (!color_management_is_scanout_allowed(img_desc, buffer)) {
 | 
			
		||||
		return SCANOUT_INELIGIBLE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// We want to ensure optimal buffer selection, but as direct-scanout can be enabled and disabled
 | 
			
		||||
	// on a frame-by-frame basis, we wait for a few frames to send the new format recommendations.
 | 
			
		||||
	// Maybe we should only send feedback in this case if tests fail.
 | 
			
		||||
| 
						 | 
				
			
			@ -2112,15 +2026,16 @@ static void scene_output_state_attempt_gamma(struct wlr_scene_output *scene_outp
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_output_state_set_color_transform(&gamma_pending, scene_output->gamma_lut_color_transform);
 | 
			
		||||
	scene_output->gamma_lut_changed = false;
 | 
			
		||||
	if (!wlr_gamma_control_v1_apply(scene_output->gamma_lut, &gamma_pending)) {
 | 
			
		||||
		wlr_output_state_finish(&gamma_pending);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scene_output->gamma_lut_changed = false;
 | 
			
		||||
	if (!wlr_output_test_state(scene_output->output, &gamma_pending)) {
 | 
			
		||||
		wlr_gamma_control_v1_send_failed_and_destroy(scene_output->gamma_lut);
 | 
			
		||||
 | 
			
		||||
		scene_output->gamma_lut = NULL;
 | 
			
		||||
		wlr_color_transform_unref(scene_output->gamma_lut_color_transform);
 | 
			
		||||
		scene_output->gamma_lut_color_transform = NULL;
 | 
			
		||||
		wlr_output_state_finish(&gamma_pending);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -2129,41 +2044,6 @@ static void scene_output_state_attempt_gamma(struct wlr_scene_output *scene_outp
 | 
			
		|||
	wlr_output_state_finish(&gamma_pending);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wlr_color_transform *scene_output_combine_color_transforms(
 | 
			
		||||
		struct wlr_scene_output *scene_output, struct wlr_color_transform *supplied) {
 | 
			
		||||
	struct wlr_color_transform *gamma_lut = scene_output->gamma_lut_color_transform;
 | 
			
		||||
	assert(gamma_lut != NULL);
 | 
			
		||||
 | 
			
		||||
	if (gamma_lut == scene_output->prev_gamma_lut_color_transform &&
 | 
			
		||||
			supplied == scene_output->prev_supplied_color_transform) {
 | 
			
		||||
		return wlr_color_transform_ref(scene_output->prev_combined_color_transform);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_color_transform *combined;
 | 
			
		||||
	if (supplied == NULL) {
 | 
			
		||||
		combined = wlr_color_transform_ref(gamma_lut);
 | 
			
		||||
	} else {
 | 
			
		||||
		struct wlr_color_transform *transforms[] = {
 | 
			
		||||
			gamma_lut,
 | 
			
		||||
			supplied,
 | 
			
		||||
		};
 | 
			
		||||
		size_t transforms_len = sizeof(transforms) / sizeof(transforms[0]);
 | 
			
		||||
		combined = wlr_color_transform_init_pipeline(transforms, transforms_len);
 | 
			
		||||
		if (combined == NULL) {
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform);
 | 
			
		||||
	scene_output->prev_gamma_lut_color_transform = wlr_color_transform_ref(gamma_lut);
 | 
			
		||||
	wlr_color_transform_unref(scene_output->prev_supplied_color_transform);
 | 
			
		||||
	scene_output->prev_supplied_color_transform = supplied ? wlr_color_transform_ref(supplied) : NULL;
 | 
			
		||||
	wlr_color_transform_unref(scene_output->prev_combined_color_transform);
 | 
			
		||||
	scene_output->prev_combined_color_transform = wlr_color_transform_ref(combined);
 | 
			
		||||
 | 
			
		||||
	return combined;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
 | 
			
		||||
		struct wlr_output_state *state, const struct wlr_scene_output_state_options *options) {
 | 
			
		||||
	struct wlr_scene_output_state_options default_options = {0};
 | 
			
		||||
| 
						 | 
				
			
			@ -2187,16 +2067,6 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
 | 
			
		|||
	enum wlr_scene_debug_damage_option debug_damage =
 | 
			
		||||
		scene_output->scene->debug_damage_option;
 | 
			
		||||
 | 
			
		||||
	bool render_gamma_lut = false;
 | 
			
		||||
	if (wlr_output_get_gamma_size(output) == 0 && output->renderer->features.output_color_transform) {
 | 
			
		||||
		if (scene_output->gamma_lut_color_transform != scene_output->prev_gamma_lut_color_transform) {
 | 
			
		||||
			scene_output_damage_whole(scene_output);
 | 
			
		||||
		}
 | 
			
		||||
		if (scene_output->gamma_lut_color_transform != NULL) {
 | 
			
		||||
			render_gamma_lut = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct render_data render_data = {
 | 
			
		||||
		.transform = output->transform,
 | 
			
		||||
		.scale = output->scale,
 | 
			
		||||
| 
						 | 
				
			
			@ -2297,7 +2167,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
 | 
			
		|||
	// - There are no color transforms that need to be applied
 | 
			
		||||
	// - Damage highlight debugging is not enabled
 | 
			
		||||
	enum scene_direct_scanout_result scanout_result = SCANOUT_INELIGIBLE;
 | 
			
		||||
	if (options->color_transform == NULL && !render_gamma_lut && list_len == 1
 | 
			
		||||
	if (options->color_transform == NULL && list_len == 1
 | 
			
		||||
			&& debug_damage != WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
 | 
			
		||||
		scanout_result = scene_entry_try_direct_scanout(&list_data[0], state, &render_data);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -2357,41 +2227,14 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
 | 
			
		|||
		timer->pre_render_duration = timespec_to_nsec(&duration);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_color_transform *color_transform = NULL;
 | 
			
		||||
	const struct wlr_color_primaries *primaries = NULL;
 | 
			
		||||
	struct wlr_color_primaries primaries_value;
 | 
			
		||||
	const struct wlr_output_image_description *img_desc = output_pending_image_description(output, state);
 | 
			
		||||
	if (img_desc != NULL) {
 | 
			
		||||
		color_transform = wlr_color_transform_init_linear_to_inverse_eotf(img_desc->transfer_function);
 | 
			
		||||
		wlr_color_primaries_from_named(&primaries_value, img_desc->primaries);
 | 
			
		||||
		primaries = &primaries_value;
 | 
			
		||||
	}
 | 
			
		||||
	if (options->color_transform != NULL) {
 | 
			
		||||
		assert(color_transform == NULL);
 | 
			
		||||
		color_transform = wlr_color_transform_ref(options->color_transform);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (render_gamma_lut) {
 | 
			
		||||
		struct wlr_color_transform *combined =
 | 
			
		||||
			scene_output_combine_color_transforms(scene_output, color_transform);
 | 
			
		||||
		wlr_color_transform_unref(color_transform);
 | 
			
		||||
		if (combined == NULL) {
 | 
			
		||||
			wlr_buffer_unlock(buffer);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		color_transform = combined;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scene_output->in_point++;
 | 
			
		||||
	struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(output->renderer, buffer,
 | 
			
		||||
			&(struct wlr_buffer_pass_options){
 | 
			
		||||
		.timer = timer ? timer->render_timer : NULL,
 | 
			
		||||
		.color_transform = color_transform,
 | 
			
		||||
		.primaries = primaries,
 | 
			
		||||
		.color_transform = options->color_transform,
 | 
			
		||||
		.signal_timeline = scene_output->in_timeline,
 | 
			
		||||
		.signal_point = scene_output->in_point,
 | 
			
		||||
	});
 | 
			
		||||
	wlr_color_transform_unref(color_transform);
 | 
			
		||||
	if (render_pass == NULL) {
 | 
			
		||||
		wlr_buffer_unlock(buffer);
 | 
			
		||||
		return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -2504,9 +2347,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
 | 
			
		|||
			scene_output->in_point);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!render_gamma_lut) {
 | 
			
		||||
		scene_output_state_attempt_gamma(scene_output, state);
 | 
			
		||||
	}
 | 
			
		||||
	scene_output_state_attempt_gamma(scene_output, state);
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2535,11 +2376,10 @@ static void scene_node_send_frame_done(struct wlr_scene_node *node,
 | 
			
		|||
	if (node->type == WLR_SCENE_NODE_BUFFER) {
 | 
			
		||||
		struct wlr_scene_buffer *scene_buffer =
 | 
			
		||||
			wlr_scene_buffer_from_node(node);
 | 
			
		||||
		struct wlr_scene_frame_done_event event = {
 | 
			
		||||
			.output = scene_output,
 | 
			
		||||
			.when = *now,
 | 
			
		||||
		};
 | 
			
		||||
		wlr_scene_buffer_send_frame_done(scene_buffer, &event);
 | 
			
		||||
 | 
			
		||||
		if (scene_buffer->primary_output == scene_output) {
 | 
			
		||||
			wlr_scene_buffer_send_frame_done(scene_buffer, now);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (node->type == WLR_SCENE_NODE_TREE) {
 | 
			
		||||
		struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
 | 
			
		||||
		struct wlr_scene_node *child;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,15 +1,12 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <wlr/types/wlr_color_management_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_compositor.h>
 | 
			
		||||
#include <wlr/types/wlr_output.h>
 | 
			
		||||
#include <wlr/util/addon.h>
 | 
			
		||||
 | 
			
		||||
#include "color-management-v1-protocol.h"
 | 
			
		||||
#include "render/color.h"
 | 
			
		||||
#include "util/mem.h"
 | 
			
		||||
 | 
			
		||||
#define COLOR_MANAGEMENT_V1_VERSION 1
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -65,6 +62,30 @@ static void resource_handle_destroy(struct wl_client *client, struct wl_resource
 | 
			
		|||
	wl_resource_destroy(resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum wlr_color_named_primaries named_primaries_to_wlr(
 | 
			
		||||
		enum wp_color_manager_v1_primaries primaries) {
 | 
			
		||||
	switch (primaries) {
 | 
			
		||||
	case WP_COLOR_MANAGER_V1_PRIMARIES_SRGB:
 | 
			
		||||
		return WLR_COLOR_NAMED_PRIMARIES_SRGB;
 | 
			
		||||
	case WP_COLOR_MANAGER_V1_PRIMARIES_BT2020:
 | 
			
		||||
		return WLR_COLOR_NAMED_PRIMARIES_BT2020;
 | 
			
		||||
	default:
 | 
			
		||||
		abort();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum wlr_color_transfer_function transfer_function_to_wlr(
 | 
			
		||||
		enum wp_color_manager_v1_transfer_function tf) {
 | 
			
		||||
	switch (tf) {
 | 
			
		||||
	case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB:
 | 
			
		||||
		return WLR_COLOR_TRANSFER_FUNCTION_SRGB;
 | 
			
		||||
	case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ:
 | 
			
		||||
		return WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
 | 
			
		||||
	default:
 | 
			
		||||
		abort();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int32_t encode_cie1931_coord(float value) {
 | 
			
		||||
	return round(value * 1000 * 1000);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -106,12 +127,10 @@ static void image_desc_handle_get_information(struct wl_client *client,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_color_primaries primaries;
 | 
			
		||||
	wlr_color_primaries_from_named(&primaries,
 | 
			
		||||
		wlr_color_manager_v1_primaries_to_wlr(image_desc->data.primaries_named));
 | 
			
		||||
	wlr_color_primaries_from_named(&primaries, named_primaries_to_wlr(image_desc->data.primaries_named));
 | 
			
		||||
 | 
			
		||||
	struct wlr_color_luminances luminances;
 | 
			
		||||
	wlr_color_transfer_function_get_default_luminance(
 | 
			
		||||
		wlr_color_manager_v1_transfer_function_to_wlr(image_desc->data.tf_named), &luminances);
 | 
			
		||||
	wlr_color_transfer_function_get_default_luminance(transfer_function_to_wlr(image_desc->data.tf_named), &luminances);
 | 
			
		||||
 | 
			
		||||
	wp_image_description_info_v1_send_primaries_named(resource, image_desc->data.primaries_named);
 | 
			
		||||
	wp_image_description_info_v1_send_primaries(resource,
 | 
			
		||||
| 
						 | 
				
			
			@ -212,14 +231,9 @@ static void cm_output_handle_get_image_description(struct wl_client *client,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_image_description_v1_data data = {
 | 
			
		||||
		.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
 | 
			
		||||
		.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
 | 
			
		||||
		.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
 | 
			
		||||
	};
 | 
			
		||||
	const struct wlr_output_image_description *image_desc = cm_output->output->image_description;
 | 
			
		||||
	if (image_desc != NULL) {
 | 
			
		||||
		data.tf_named = wlr_color_manager_v1_transfer_function_from_wlr(image_desc->transfer_function);
 | 
			
		||||
		data.primaries_named = wlr_color_manager_v1_primaries_from_wlr(image_desc->primaries);
 | 
			
		||||
	}
 | 
			
		||||
	image_desc_create_ready(cm_output->manager, cm_output_resource, id, &data, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -292,13 +306,6 @@ static void cm_surface_handle_set_image_description(struct wl_client *client,
 | 
			
		|||
 | 
			
		||||
	struct wlr_image_description_v1 *image_desc = image_desc_from_resource(image_desc_resource);
 | 
			
		||||
 | 
			
		||||
	if (image_desc == NULL) {
 | 
			
		||||
		wl_resource_post_error(cm_surface_resource,
 | 
			
		||||
			WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_IMAGE_DESCRIPTION,
 | 
			
		||||
			"Image description to be set is invalid");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool found = false;
 | 
			
		||||
	for (size_t i = 0; i < cm_surface->manager->render_intents_len; i++) {
 | 
			
		||||
		if (cm_surface->manager->render_intents[i] == render_intent) {
 | 
			
		||||
| 
						 | 
				
			
			@ -666,35 +673,29 @@ static void manager_handle_get_output(struct wl_client *client,
 | 
			
		|||
	struct wlr_color_manager_v1 *manager = manager_from_resource(manager_resource);
 | 
			
		||||
	struct wlr_output *output = wlr_output_from_resource(output_resource);
 | 
			
		||||
 | 
			
		||||
	uint32_t version = wl_resource_get_version(manager_resource);
 | 
			
		||||
	struct wl_resource *cm_output_resource = wl_resource_create(client,
 | 
			
		||||
		&wp_color_management_output_v1_interface, version, id);
 | 
			
		||||
	if (!cm_output_resource) {
 | 
			
		||||
		wl_client_post_no_memory(client);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	wl_resource_set_implementation(cm_output_resource, &cm_output_impl,
 | 
			
		||||
		NULL, cm_output_handle_resource_destroy);
 | 
			
		||||
 | 
			
		||||
	if (output == NULL) {
 | 
			
		||||
		return; // leave the wp_color_management_output_v1 resource inert
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_color_management_output_v1 *cm_output = calloc(1, sizeof(*cm_output));
 | 
			
		||||
	if (cm_output == NULL) {
 | 
			
		||||
		wl_client_post_no_memory(client);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cm_output->resource = cm_output_resource;
 | 
			
		||||
	cm_output->manager = manager;
 | 
			
		||||
	cm_output->output = output;
 | 
			
		||||
 | 
			
		||||
	uint32_t version = wl_resource_get_version(manager_resource);
 | 
			
		||||
	cm_output->resource = wl_resource_create(client,
 | 
			
		||||
		&wp_color_management_output_v1_interface, version, id);
 | 
			
		||||
	if (!cm_output->resource) {
 | 
			
		||||
		wl_client_post_no_memory(client);
 | 
			
		||||
		free(cm_output);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	wl_resource_set_implementation(cm_output->resource, &cm_output_impl,
 | 
			
		||||
		cm_output, cm_output_handle_resource_destroy);
 | 
			
		||||
 | 
			
		||||
	cm_output->output_destroy.notify = cm_output_handle_output_destroy;
 | 
			
		||||
	wl_signal_add(&output->events.destroy, &cm_output->output_destroy);
 | 
			
		||||
 | 
			
		||||
	wl_list_insert(&manager->outputs, &cm_output->link);
 | 
			
		||||
	wl_resource_set_user_data(cm_output->resource, cm_output);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wlr_color_management_surface_v1 *cm_surface_from_surface(struct wlr_surface *surface) {
 | 
			
		||||
| 
						 | 
				
			
			@ -777,7 +778,7 @@ static void manager_handle_get_surface_feedback(struct wl_client *client,
 | 
			
		|||
 | 
			
		||||
	surface_feedback->surface = surface;
 | 
			
		||||
	surface_feedback->data = (struct wlr_image_description_v1_data){
 | 
			
		||||
		.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
 | 
			
		||||
		.tf_named = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
 | 
			
		||||
		.primaries_named = WP_COLOR_MANAGER_V1_PRIMARIES_SRGB,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -887,8 +888,6 @@ static void manager_bind(struct wl_client *client, void *data,
 | 
			
		|||
 | 
			
		||||
static void manager_handle_display_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wlr_color_manager_v1 *manager = wl_container_of(listener, manager, display_destroy);
 | 
			
		||||
	wl_signal_emit_mutable(&manager->events.destroy, NULL);
 | 
			
		||||
	assert(wl_list_empty(&manager->events.destroy.listener_list));
 | 
			
		||||
	wl_list_remove(&manager->display_destroy.link);
 | 
			
		||||
	wl_global_destroy(manager->global);
 | 
			
		||||
	free(manager->render_intents);
 | 
			
		||||
| 
						 | 
				
			
			@ -897,6 +896,17 @@ static void manager_handle_display_destroy(struct wl_listener *listener, void *d
 | 
			
		|||
	free(manager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool memdup(void *out, const void *src, size_t size) {
 | 
			
		||||
	void *dst = malloc(size);
 | 
			
		||||
	if (dst == NULL) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(dst, src, size);
 | 
			
		||||
	void **dst_ptr = out;
 | 
			
		||||
	*dst_ptr = dst;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
	assert(version <= COLOR_MANAGEMENT_V1_VERSION);
 | 
			
		||||
| 
						 | 
				
			
			@ -936,7 +946,6 @@ struct wlr_color_manager_v1 *wlr_color_manager_v1_create(struct wl_display *disp
 | 
			
		|||
	manager->transfer_functions_len = options->transfer_functions_len;
 | 
			
		||||
	manager->primaries_len = options->primaries_len;
 | 
			
		||||
 | 
			
		||||
	wl_signal_init(&manager->events.destroy);
 | 
			
		||||
	wl_list_init(&manager->outputs);
 | 
			
		||||
	wl_list_init(&manager->surface_feedbacks);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -983,61 +992,3 @@ void wlr_color_manager_v1_set_surface_preferred_image_description(
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum wlr_color_transfer_function
 | 
			
		||||
wlr_color_manager_v1_transfer_function_to_wlr(enum wp_color_manager_v1_transfer_function tf) {
 | 
			
		||||
	switch (tf) {
 | 
			
		||||
	case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB:
 | 
			
		||||
		return WLR_COLOR_TRANSFER_FUNCTION_SRGB;
 | 
			
		||||
	case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ:
 | 
			
		||||
		return WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ;
 | 
			
		||||
	case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR:
 | 
			
		||||
		return WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR;
 | 
			
		||||
	case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22:
 | 
			
		||||
		return WLR_COLOR_TRANSFER_FUNCTION_GAMMA22;
 | 
			
		||||
	case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886:
 | 
			
		||||
		return WLR_COLOR_TRANSFER_FUNCTION_BT1886;
 | 
			
		||||
	default:
 | 
			
		||||
		abort();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum wp_color_manager_v1_transfer_function
 | 
			
		||||
wlr_color_manager_v1_transfer_function_from_wlr(enum wlr_color_transfer_function tf) {
 | 
			
		||||
	switch (tf) {
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
 | 
			
		||||
		return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB;
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
 | 
			
		||||
		return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ;
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
 | 
			
		||||
		return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR;
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
 | 
			
		||||
		return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22;
 | 
			
		||||
	case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
 | 
			
		||||
		return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886;
 | 
			
		||||
	}
 | 
			
		||||
	abort();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum wlr_color_named_primaries
 | 
			
		||||
wlr_color_manager_v1_primaries_to_wlr(enum wp_color_manager_v1_primaries primaries) {
 | 
			
		||||
	switch (primaries) {
 | 
			
		||||
	case WP_COLOR_MANAGER_V1_PRIMARIES_SRGB:
 | 
			
		||||
		return WLR_COLOR_NAMED_PRIMARIES_SRGB;
 | 
			
		||||
	case WP_COLOR_MANAGER_V1_PRIMARIES_BT2020:
 | 
			
		||||
		return WLR_COLOR_NAMED_PRIMARIES_BT2020;
 | 
			
		||||
	default:
 | 
			
		||||
		abort();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum wp_color_manager_v1_primaries
 | 
			
		||||
wlr_color_manager_v1_primaries_from_wlr(enum wlr_color_named_primaries primaries) {
 | 
			
		||||
	switch (primaries) {
 | 
			
		||||
	case WLR_COLOR_NAMED_PRIMARIES_SRGB:
 | 
			
		||||
		return WP_COLOR_MANAGER_V1_PRIMARIES_SRGB;
 | 
			
		||||
	case WLR_COLOR_NAMED_PRIMARIES_BT2020:
 | 
			
		||||
		return WP_COLOR_MANAGER_V1_PRIMARIES_BT2020;
 | 
			
		||||
	}
 | 
			
		||||
	abort();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,410 +0,0 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include <wlr/types/wlr_compositor.h>
 | 
			
		||||
#include <wlr/types/wlr_color_representation_v1.h>
 | 
			
		||||
#include <wlr/util/addon.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
 | 
			
		||||
#include "color-representation-v1-protocol.h"
 | 
			
		||||
#include "util/mem.h"
 | 
			
		||||
 | 
			
		||||
#define WP_COLOR_REPRESENTATION_VERSION 1
 | 
			
		||||
 | 
			
		||||
enum wlr_alpha_mode wlr_color_representation_v1_alpha_mode_to_wlr(
 | 
			
		||||
		enum wp_color_representation_surface_v1_alpha_mode wp_val) {
 | 
			
		||||
	switch (wp_val) {
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL:
 | 
			
		||||
		return WLR_COLOR_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_ALPHA_MODE_PREMULTIPLIED_OPTICAL:
 | 
			
		||||
		return WLR_COLOR_ALPHA_MODE_PREMULTIPLIED_OPTICAL;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_ALPHA_MODE_STRAIGHT:
 | 
			
		||||
		return WLR_COLOR_ALPHA_MODE_STRAIGHT;
 | 
			
		||||
	}
 | 
			
		||||
	abort(); // unreachable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum wlr_color_encoding wlr_color_representation_v1_color_encoding_to_wlr(
 | 
			
		||||
		enum wp_color_representation_surface_v1_coefficients wp_val) {
 | 
			
		||||
	switch (wp_val) {
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_IDENTITY:
 | 
			
		||||
		return WLR_COLOR_ENCODING_IDENTITY;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT709:
 | 
			
		||||
		return WLR_COLOR_ENCODING_BT709;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_FCC:
 | 
			
		||||
		return WLR_COLOR_ENCODING_FCC;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT601:
 | 
			
		||||
		return WLR_COLOR_ENCODING_BT601;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_SMPTE240:
 | 
			
		||||
		return WLR_COLOR_ENCODING_SMPTE240;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT2020:
 | 
			
		||||
		return WLR_COLOR_ENCODING_BT2020;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT2020_CL:
 | 
			
		||||
		return WLR_COLOR_ENCODING_BT2020_CL;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_ICTCP:
 | 
			
		||||
		return WLR_COLOR_ENCODING_ICTCP;
 | 
			
		||||
	}
 | 
			
		||||
	abort(); // unreachable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum wlr_color_range wlr_color_representation_v1_color_range_to_wlr(
 | 
			
		||||
		enum wp_color_representation_surface_v1_range wp_val) {
 | 
			
		||||
	switch (wp_val) {
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_LIMITED:
 | 
			
		||||
		return  WLR_COLOR_RANGE_LIMITED;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_FULL:
 | 
			
		||||
		return WLR_COLOR_RANGE_FULL;
 | 
			
		||||
	}
 | 
			
		||||
	abort(); // unreachable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum wlr_color_chroma_location wlr_color_representation_v1_chroma_location_to_wlr(
 | 
			
		||||
		enum wp_color_representation_surface_v1_chroma_location wp_val) {
 | 
			
		||||
	switch (wp_val) {
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_0:
 | 
			
		||||
		return WLR_COLOR_CHROMA_LOCATION_TYPE0;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_1:
 | 
			
		||||
		return WLR_COLOR_CHROMA_LOCATION_TYPE1;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_2:
 | 
			
		||||
		return WLR_COLOR_CHROMA_LOCATION_TYPE2;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_3:
 | 
			
		||||
		return WLR_COLOR_CHROMA_LOCATION_TYPE3;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_4:
 | 
			
		||||
		return WLR_COLOR_CHROMA_LOCATION_TYPE4;
 | 
			
		||||
	case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_5:
 | 
			
		||||
		return WLR_COLOR_CHROMA_LOCATION_TYPE5;
 | 
			
		||||
	}
 | 
			
		||||
	abort(); // unreachable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct wlr_color_representation_v1 {
 | 
			
		||||
	struct wl_resource *resource;
 | 
			
		||||
	struct wlr_surface *surface;
 | 
			
		||||
 | 
			
		||||
	struct wlr_color_representation_manager_v1 *manager;
 | 
			
		||||
 | 
			
		||||
	// Associate the wlr_color_representation_v1 with a wlr_surface
 | 
			
		||||
	struct wlr_addon addon;
 | 
			
		||||
 | 
			
		||||
	struct wlr_surface_synced synced;
 | 
			
		||||
	struct wlr_color_representation_v1_surface_state pending, current;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct wp_color_representation_surface_v1_interface color_repr_impl;
 | 
			
		||||
 | 
			
		||||
static struct wlr_color_representation_v1 *color_repr_from_resource(
 | 
			
		||||
		struct wl_resource *resource) {
 | 
			
		||||
	assert(wl_resource_instance_of(resource,
 | 
			
		||||
		&wp_color_representation_surface_v1_interface,
 | 
			
		||||
		&color_repr_impl));
 | 
			
		||||
	return wl_resource_get_user_data(resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void color_repr_handle_destroy(struct wl_client *client,
 | 
			
		||||
		struct wl_resource *resource) {
 | 
			
		||||
	// Actual destroying is done by the resource-destroy handler
 | 
			
		||||
	wl_resource_destroy(resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void color_repr_handle_set_alpha_mode(struct wl_client *client,
 | 
			
		||||
		struct wl_resource *resource, uint32_t alpha_mode) {
 | 
			
		||||
	struct wlr_color_representation_v1 *color_repr =
 | 
			
		||||
		color_repr_from_resource(resource);
 | 
			
		||||
	if (color_repr == NULL) {
 | 
			
		||||
		wl_resource_post_error(resource, WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_INERT,
 | 
			
		||||
			"Associated surface has been destroyed, object is inert");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool found = false;
 | 
			
		||||
	for (size_t i = 0; i < color_repr->manager->supported_alpha_modes_len; i++) {
 | 
			
		||||
		if (color_repr->manager->supported_alpha_modes[i] == alpha_mode) {
 | 
			
		||||
			found = true;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (!found) {
 | 
			
		||||
		wl_resource_post_error(resource,
 | 
			
		||||
			WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_ALPHA_MODE,
 | 
			
		||||
			"Unsupported alpha mode");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	color_repr->pending.alpha_mode = alpha_mode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void color_repr_handle_set_coefficients_and_range(struct wl_client *client,
 | 
			
		||||
		struct wl_resource *resource, uint32_t coefficients,
 | 
			
		||||
		uint32_t range) {
 | 
			
		||||
	struct wlr_color_representation_v1 *color_repr =
 | 
			
		||||
		color_repr_from_resource(resource);
 | 
			
		||||
	if (color_repr == NULL) {
 | 
			
		||||
		wl_resource_post_error(resource, WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_INERT,
 | 
			
		||||
			"Associated surface has been destroyed, object is inert");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool found = false;
 | 
			
		||||
	for (size_t i = 0; i < color_repr->manager->supported_coeffs_and_ranges_len; i++) {
 | 
			
		||||
		struct wlr_color_representation_v1_coeffs_and_range *supported =
 | 
			
		||||
			&color_repr->manager->supported_coeffs_and_ranges[i];
 | 
			
		||||
		if (supported->coeffs == coefficients && supported->range == range) {
 | 
			
		||||
			found = true;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (!found) {
 | 
			
		||||
		wl_resource_post_error(resource,
 | 
			
		||||
			WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_COEFFICIENTS,
 | 
			
		||||
			"Unsupported coefficients/range pair");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	color_repr->pending.coefficients = coefficients;
 | 
			
		||||
	color_repr->pending.range = range;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void color_repr_handle_set_chroma_location(struct wl_client *client,
 | 
			
		||||
		struct wl_resource *resource, uint32_t chroma_location) {
 | 
			
		||||
	struct wlr_color_representation_v1 *color_repr =
 | 
			
		||||
		color_repr_from_resource(resource);
 | 
			
		||||
	if (color_repr == NULL) {
 | 
			
		||||
		wl_resource_post_error(resource, WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_INERT,
 | 
			
		||||
			"Associated surface has been destroyed, object is inert");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t version = wl_resource_get_version(resource);
 | 
			
		||||
	if (!wp_color_representation_surface_v1_chroma_location_is_valid(
 | 
			
		||||
			version, chroma_location)) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "Client sent chroma location which isn't a valid enum value");
 | 
			
		||||
		// TODO: Post actual error once
 | 
			
		||||
		// https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/429
 | 
			
		||||
		// is merged and wlroots depends on a new enough wayland-protocols.
 | 
			
		||||
		wl_client_post_implementation_error(resource->client,
 | 
			
		||||
			"Chroma location is not a valid enum value");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// In this protocol there's no concept of supported chroma locations
 | 
			
		||||
	// from a client point-of-view. The compositor should just ignore any
 | 
			
		||||
	// chroma locations it doesn't know what to do with.
 | 
			
		||||
 | 
			
		||||
	color_repr->pending.chroma_location = chroma_location;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wp_color_representation_surface_v1_interface color_repr_impl = {
 | 
			
		||||
	.destroy = color_repr_handle_destroy,
 | 
			
		||||
	.set_alpha_mode = color_repr_handle_set_alpha_mode,
 | 
			
		||||
	.set_coefficients_and_range = color_repr_handle_set_coefficients_and_range,
 | 
			
		||||
	.set_chroma_location = color_repr_handle_set_chroma_location,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void color_repr_destroy(struct wlr_color_representation_v1 *color_repr) {
 | 
			
		||||
	if (color_repr == NULL) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	wlr_surface_synced_finish(&color_repr->synced);
 | 
			
		||||
	wlr_addon_finish(&color_repr->addon);
 | 
			
		||||
	wl_resource_set_user_data(color_repr->resource, NULL);
 | 
			
		||||
	free(color_repr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void color_repr_addon_destroy(struct wlr_addon *addon) {
 | 
			
		||||
	struct wlr_color_representation_v1 *color_repr =
 | 
			
		||||
		wl_container_of(addon, color_repr, addon);
 | 
			
		||||
	color_repr_destroy(color_repr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wlr_addon_interface surface_addon_impl = {
 | 
			
		||||
	.name = "wlr_color_representation_v1",
 | 
			
		||||
	.destroy = color_repr_addon_destroy,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void color_repr_handle_resource_destroy(struct wl_resource *resource) {
 | 
			
		||||
	struct wlr_color_representation_v1 *color_repr =
 | 
			
		||||
		color_repr_from_resource(resource);
 | 
			
		||||
	color_repr_destroy(color_repr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void color_repr_manager_handle_destroy(struct wl_client *client,
 | 
			
		||||
		struct wl_resource *resource) {
 | 
			
		||||
	// Actual destroying is done by the resource-destroy handler
 | 
			
		||||
	wl_resource_destroy(resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wlr_surface_synced_impl surface_synced_impl = {
 | 
			
		||||
	.state_size = sizeof(struct wlr_color_representation_v1_surface_state),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct wlr_color_representation_v1 *color_repr_from_surface(
 | 
			
		||||
		struct wlr_surface *surface) {
 | 
			
		||||
	struct wlr_addon *addon = wlr_addon_find(&surface->addons, NULL, &surface_addon_impl);
 | 
			
		||||
	if (addon == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	struct wlr_color_representation_v1 *color_repr = wl_container_of(addon, color_repr, addon);
 | 
			
		||||
	return color_repr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wp_color_representation_manager_v1_interface color_repr_manager_impl;
 | 
			
		||||
 | 
			
		||||
static struct wlr_color_representation_manager_v1 *manager_from_resource(
 | 
			
		||||
		struct wl_resource *resource) {
 | 
			
		||||
	assert(wl_resource_instance_of(resource,
 | 
			
		||||
		&wp_color_representation_manager_v1_interface,
 | 
			
		||||
		&color_repr_manager_impl));
 | 
			
		||||
	return wl_resource_get_user_data(resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void color_repr_manager_handle_get_surface(struct wl_client *client,
 | 
			
		||||
		struct wl_resource *manager_resource,
 | 
			
		||||
		uint32_t color_repr_id,
 | 
			
		||||
		struct wl_resource *surface_resource) {
 | 
			
		||||
	struct wlr_surface *surface = wlr_surface_from_resource(surface_resource);
 | 
			
		||||
 | 
			
		||||
	// Check if there's already a color-representation attached to
 | 
			
		||||
	// this surface
 | 
			
		||||
	if (color_repr_from_surface(surface) != NULL) {
 | 
			
		||||
		wl_resource_post_error(manager_resource,
 | 
			
		||||
			WP_COLOR_REPRESENTATION_MANAGER_V1_ERROR_SURFACE_EXISTS,
 | 
			
		||||
			"wp_color_representation_surface_v1 already exists for this surface");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_color_representation_v1 *color_repr = calloc(1, sizeof(*color_repr));
 | 
			
		||||
	if (!color_repr) {
 | 
			
		||||
		wl_resource_post_no_memory(manager_resource);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	color_repr->manager = manager_from_resource(manager_resource);
 | 
			
		||||
 | 
			
		||||
	if (!wlr_surface_synced_init(&color_repr->synced, surface,
 | 
			
		||||
			&surface_synced_impl, &color_repr->pending, &color_repr->current)) {
 | 
			
		||||
		free(color_repr);
 | 
			
		||||
		wl_resource_post_no_memory(manager_resource);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t version = wl_resource_get_version(manager_resource);
 | 
			
		||||
	color_repr->resource = wl_resource_create(client,
 | 
			
		||||
		&wp_color_representation_surface_v1_interface, version, color_repr_id);
 | 
			
		||||
	if (color_repr->resource == NULL) {
 | 
			
		||||
		wlr_surface_synced_finish(&color_repr->synced);
 | 
			
		||||
		free(color_repr);
 | 
			
		||||
		wl_resource_post_no_memory(manager_resource);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	wl_resource_set_implementation(color_repr->resource,
 | 
			
		||||
		&color_repr_impl, color_repr, color_repr_handle_resource_destroy);
 | 
			
		||||
 | 
			
		||||
	wlr_addon_init(&color_repr->addon, &surface->addons, NULL, &surface_addon_impl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wp_color_representation_manager_v1_interface color_repr_manager_impl = {
 | 
			
		||||
	.destroy = color_repr_manager_handle_destroy,
 | 
			
		||||
	.get_surface = color_repr_manager_handle_get_surface,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void send_supported(struct wlr_color_representation_manager_v1 *manager,
 | 
			
		||||
		struct wl_resource *resource) {
 | 
			
		||||
	for (size_t i = 0; i < manager->supported_alpha_modes_len; i++) {
 | 
			
		||||
		wp_color_representation_manager_v1_send_supported_alpha_mode(
 | 
			
		||||
			resource, manager->supported_alpha_modes[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < manager->supported_coeffs_and_ranges_len; i++) {
 | 
			
		||||
		struct wlr_color_representation_v1_coeffs_and_range *supported =
 | 
			
		||||
			&manager->supported_coeffs_and_ranges[i];
 | 
			
		||||
		wp_color_representation_manager_v1_send_supported_coefficients_and_ranges(
 | 
			
		||||
			resource, supported->coeffs, supported->range);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Note that there is no event for supported chroma locations in the
 | 
			
		||||
	// v1 protocol.
 | 
			
		||||
 | 
			
		||||
	wp_color_representation_manager_v1_send_done(resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void manager_bind(struct wl_client *client, void *data,
 | 
			
		||||
		uint32_t version, uint32_t id) {
 | 
			
		||||
	struct wlr_color_representation_manager_v1 *manager = data;
 | 
			
		||||
 | 
			
		||||
	struct wl_resource *resource = wl_resource_create(client,
 | 
			
		||||
		&wp_color_representation_manager_v1_interface,
 | 
			
		||||
		version, id);
 | 
			
		||||
	if (resource == NULL) {
 | 
			
		||||
		wl_client_post_no_memory(client);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	wl_resource_set_implementation(resource, &color_repr_manager_impl, manager, NULL);
 | 
			
		||||
 | 
			
		||||
	send_supported(manager, resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_display_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wlr_color_representation_manager_v1 *manager =
 | 
			
		||||
		wl_container_of(listener, manager, display_destroy);
 | 
			
		||||
 | 
			
		||||
	wl_signal_emit_mutable(&manager->events.destroy, NULL);
 | 
			
		||||
 | 
			
		||||
	assert(wl_list_empty(&manager->events.destroy.listener_list));
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&manager->display_destroy.link);
 | 
			
		||||
	wl_global_destroy(manager->global);
 | 
			
		||||
	free(manager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
	assert(version <= WP_COLOR_REPRESENTATION_VERSION);
 | 
			
		||||
 | 
			
		||||
	struct wlr_color_representation_manager_v1 *manager = calloc(1, sizeof(*manager));
 | 
			
		||||
	if (manager == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool ok = true;
 | 
			
		||||
	ok &= memdup(&manager->supported_alpha_modes,
 | 
			
		||||
		options->supported_alpha_modes,
 | 
			
		||||
		sizeof(options->supported_alpha_modes[0]) * options->supported_alpha_modes_len);
 | 
			
		||||
	manager->supported_alpha_modes_len = options->supported_alpha_modes_len;
 | 
			
		||||
	ok &= memdup(&manager->supported_coeffs_and_ranges,
 | 
			
		||||
		options->supported_coeffs_and_ranges,
 | 
			
		||||
		sizeof(options->supported_coeffs_and_ranges[0]) * options->supported_coeffs_and_ranges_len);
 | 
			
		||||
	manager->supported_coeffs_and_ranges_len = options->supported_coeffs_and_ranges_len;
 | 
			
		||||
	if (!ok) {
 | 
			
		||||
		goto err_options;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	manager->global = wl_global_create(display,
 | 
			
		||||
		&wp_color_representation_manager_v1_interface,
 | 
			
		||||
		version, manager, manager_bind);
 | 
			
		||||
	if (manager->global == NULL) {
 | 
			
		||||
		goto err_options;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_signal_init(&manager->events.destroy);
 | 
			
		||||
 | 
			
		||||
	manager->display_destroy.notify = handle_display_destroy;
 | 
			
		||||
	wl_display_add_destroy_listener(display, &manager->display_destroy);
 | 
			
		||||
 | 
			
		||||
	return manager;
 | 
			
		||||
 | 
			
		||||
err_options:
 | 
			
		||||
	free(manager->supported_alpha_modes);
 | 
			
		||||
	free(manager->supported_coeffs_and_ranges);
 | 
			
		||||
	free(manager);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct wlr_color_representation_v1_surface_state *wlr_color_representation_v1_get_surface_state(
 | 
			
		||||
		struct wlr_surface *surface) {
 | 
			
		||||
	struct wlr_color_representation_v1 *color_repr = color_repr_from_surface(surface);
 | 
			
		||||
	if (color_repr == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	return &color_repr->current;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -882,7 +882,11 @@ void wlr_surface_reject_pending(struct wlr_surface *surface, struct wl_resource
 | 
			
		|||
	va_list args;
 | 
			
		||||
	va_start(args, msg);
 | 
			
		||||
 | 
			
		||||
	wl_resource_post_error_vargs(resource, code, msg, args);
 | 
			
		||||
	// XXX: libwayland could expose wl_resource_post_error_vargs() instead
 | 
			
		||||
	char buffer[128]; // Matches the size of the buffer used in libwayland
 | 
			
		||||
	vsnprintf(buffer, sizeof(buffer), msg, args);
 | 
			
		||||
 | 
			
		||||
	wl_resource_post_error(resource, code, "%s", buffer);
 | 
			
		||||
	surface->pending_rejected = true;
 | 
			
		||||
 | 
			
		||||
	va_end(args);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,6 @@
 | 
			
		|||
#include <wlr/types/wlr_content_type_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_compositor.h>
 | 
			
		||||
 | 
			
		||||
#include "content-type-v1-protocol.h"
 | 
			
		||||
 | 
			
		||||
#define CONTENT_TYPE_VERSION 1
 | 
			
		||||
 | 
			
		||||
struct wlr_content_type_v1_surface {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -530,6 +530,10 @@ static void cursor_output_cursor_update(struct wlr_cursor_output_cursor *output_
 | 
			
		|||
	struct wlr_cursor *cur = output_cursor->cursor;
 | 
			
		||||
	struct wlr_output *output = output_cursor->output_cursor->output;
 | 
			
		||||
 | 
			
		||||
	if (!output->enabled) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cursor_output_cursor_reset_image(output_cursor);
 | 
			
		||||
 | 
			
		||||
	if (cur->state->buffer != NULL) {
 | 
			
		||||
| 
						 | 
				
			
			@ -585,11 +589,10 @@ static void cursor_output_cursor_update(struct wlr_cursor_output_cursor *output_
 | 
			
		|||
			&src_box, dst_width, dst_height, surface->current.transform,
 | 
			
		||||
			hotspot_x, hotspot_y, wait_timeline, wait_point);
 | 
			
		||||
 | 
			
		||||
		if (syncobj_surface_state != NULL &&
 | 
			
		||||
				surface->buffer != NULL && surface->buffer->source != NULL &&
 | 
			
		||||
		if (syncobj_surface_state != NULL && surface->buffer != NULL &&
 | 
			
		||||
				(surface->current.committed & WLR_SURFACE_STATE_BUFFER)) {
 | 
			
		||||
			wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(syncobj_surface_state,
 | 
			
		||||
				surface->buffer->source);
 | 
			
		||||
				&surface->buffer->base);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (output_cursor->output_cursor->visible) {
 | 
			
		||||
| 
						 | 
				
			
			@ -647,7 +650,7 @@ static void output_cursor_output_handle_output_commit(
 | 
			
		|||
	struct wlr_surface *surface = output_cursor->cursor->state->surface;
 | 
			
		||||
	if (surface && output_cursor->output_cursor->visible &&
 | 
			
		||||
			(event->state->committed & WLR_OUTPUT_STATE_BUFFER)) {
 | 
			
		||||
		wlr_surface_send_frame_done(surface, &event->when);
 | 
			
		||||
		wlr_surface_send_frame_done(surface, event->when);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,11 +5,9 @@
 | 
			
		|||
#include <wlr/types/wlr_cursor_shape_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_seat.h>
 | 
			
		||||
#include <wlr/types/wlr_tablet_tool.h>
 | 
			
		||||
 | 
			
		||||
#include "cursor-shape-v1-protocol.h"
 | 
			
		||||
#include "types/wlr_tablet_v2.h"
 | 
			
		||||
 | 
			
		||||
#define CURSOR_SHAPE_MANAGER_V1_VERSION 2
 | 
			
		||||
#define CURSOR_SHAPE_MANAGER_V1_VERSION 1
 | 
			
		||||
 | 
			
		||||
struct wlr_cursor_shape_device_v1 {
 | 
			
		||||
	struct wl_resource *resource;
 | 
			
		||||
| 
						 | 
				
			
			@ -48,8 +46,7 @@ static void device_handle_set_shape(struct wl_client *client, struct wl_resource
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t version = wl_resource_get_version(device_resource);
 | 
			
		||||
	if (!wp_cursor_shape_device_v1_shape_is_valid(shape, version)) {
 | 
			
		||||
	if (shape == 0 || shape > WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT) {
 | 
			
		||||
		wl_resource_post_error(device_resource, WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE,
 | 
			
		||||
			"Invalid shape %"PRIu32, shape);
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -259,8 +256,6 @@ static const char *const shape_names[] = {
 | 
			
		|||
	[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_SCROLL] = "all-scroll",
 | 
			
		||||
	[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_IN] = "zoom-in",
 | 
			
		||||
	[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT] = "zoom-out",
 | 
			
		||||
	[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DND_ASK] = "dnd-ask",
 | 
			
		||||
	[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_RESIZE] = "all-resize",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const char *wlr_cursor_shape_v1_name(enum wp_cursor_shape_device_v1_shape shape) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -68,6 +68,10 @@ static void drm_lease_connector_v1_destroy(
 | 
			
		|||
 | 
			
		||||
	wlr_log(WLR_DEBUG, "Destroying connector %s", connector->output->name);
 | 
			
		||||
 | 
			
		||||
	if (connector->active_lease) {
 | 
			
		||||
		wlr_drm_lease_terminate(connector->active_lease->drm_lease);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wl_resource *resource, *tmp;
 | 
			
		||||
	wl_resource_for_each_safe(resource, tmp, &connector->resources) {
 | 
			
		||||
		wp_drm_lease_connector_v1_send_withdrawn(resource);
 | 
			
		||||
| 
						 | 
				
			
			@ -136,9 +140,14 @@ static void lease_handle_destroy(struct wl_listener *listener, void *data) {
 | 
			
		|||
 | 
			
		||||
	wl_list_remove(&lease->destroy.link);
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < lease->n_connectors; ++i) {
 | 
			
		||||
		lease->connectors[i]->active_lease = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&lease->link);
 | 
			
		||||
	wl_resource_set_user_data(lease->resource, NULL);
 | 
			
		||||
 | 
			
		||||
	free(lease->connectors);
 | 
			
		||||
	free(lease);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -171,6 +180,20 @@ struct wlr_drm_lease_v1 *wlr_drm_lease_request_v1_grant(
 | 
			
		|||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lease->connectors = calloc(request->n_connectors, sizeof(*lease->connectors));
 | 
			
		||||
	if (!lease->connectors) {
 | 
			
		||||
		wlr_log(WLR_ERROR, "Failed to allocate lease connectors list");
 | 
			
		||||
		close(fd);
 | 
			
		||||
		wp_drm_lease_v1_send_finished(lease->resource);
 | 
			
		||||
		free(lease);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	lease->n_connectors = request->n_connectors;
 | 
			
		||||
	for (size_t i = 0; i < request->n_connectors; ++i) {
 | 
			
		||||
		lease->connectors[i] = request->connectors[i];
 | 
			
		||||
		lease->connectors[i]->active_lease = lease;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lease->destroy.notify = lease_handle_destroy;
 | 
			
		||||
	wl_signal_add(&lease->drm_lease->events.destroy, &lease->destroy);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -315,6 +338,16 @@ static void drm_lease_request_v1_handle_submit(
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (size_t i = 0; i < request->n_connectors; ++i) {
 | 
			
		||||
		struct wlr_drm_lease_connector_v1 *conn = request->connectors[i];
 | 
			
		||||
		if (conn->active_lease) {
 | 
			
		||||
			wlr_log(WLR_ERROR, "Failed to create lease, connector %s has "
 | 
			
		||||
					"already been leased", conn->output->name);
 | 
			
		||||
			wp_drm_lease_v1_send_finished(lease_resource);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	request->lease_resource = lease_resource;
 | 
			
		||||
 | 
			
		||||
	wl_signal_emit_mutable(&request->device->manager->events.request,
 | 
			
		||||
| 
						 | 
				
			
			@ -407,6 +440,10 @@ static struct wp_drm_lease_connector_v1_interface lease_connector_impl = {
 | 
			
		|||
static void drm_lease_connector_v1_send_to_client(
 | 
			
		||||
		struct wlr_drm_lease_connector_v1 *connector,
 | 
			
		||||
		struct wl_resource *resource) {
 | 
			
		||||
	if (connector->active_lease) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct wl_client *client = wl_resource_get_client(resource);
 | 
			
		||||
 | 
			
		||||
	uint32_t version = wl_resource_get_version(resource);
 | 
			
		||||
| 
						 | 
				
			
			@ -453,12 +490,10 @@ static void lease_device_bind(struct wl_client *wl_client, void *data,
 | 
			
		|||
	if (!device) {
 | 
			
		||||
		wlr_log(WLR_DEBUG, "Failed to bind lease device, "
 | 
			
		||||
				"the wlr_drm_lease_device_v1 has been destroyed");
 | 
			
		||||
		wl_list_init(wl_resource_get_link(device_resource));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_resource_set_user_data(device_resource, device);
 | 
			
		||||
	wl_list_insert(&device->resources, wl_resource_get_link(device_resource));
 | 
			
		||||
 | 
			
		||||
	int fd = wlr_drm_backend_get_non_master_fd(device->backend);
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -470,6 +505,8 @@ static void lease_device_bind(struct wl_client *wl_client, void *data,
 | 
			
		|||
	wp_drm_lease_device_v1_send_drm_fd(device_resource, fd);
 | 
			
		||||
	close(fd);
 | 
			
		||||
 | 
			
		||||
	wl_list_insert(&device->resources, wl_resource_get_link(device_resource));
 | 
			
		||||
 | 
			
		||||
	struct wlr_drm_lease_connector_v1 *connector;
 | 
			
		||||
	wl_list_for_each(connector, &device->connectors, link) {
 | 
			
		||||
		drm_lease_connector_v1_send_to_client(connector, device_resource);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,11 +85,11 @@ static void frame_output_handle_commit(struct wl_listener *listener,
 | 
			
		|||
			attribs.fd[i], size, attribs.offset[i], attribs.stride[i], i);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	time_t tv_sec = event->when.tv_sec;
 | 
			
		||||
	time_t tv_sec = event->when->tv_sec;
 | 
			
		||||
	uint32_t tv_sec_hi = (sizeof(tv_sec) > 4) ? tv_sec >> 32 : 0;
 | 
			
		||||
	uint32_t tv_sec_lo = tv_sec & 0xFFFFFFFF;
 | 
			
		||||
	zwlr_export_dmabuf_frame_v1_send_ready(frame->resource,
 | 
			
		||||
		tv_sec_hi, tv_sec_lo, event->when.tv_nsec);
 | 
			
		||||
		tv_sec_hi, tv_sec_lo, event->when->tv_nsec);
 | 
			
		||||
	frame_destroy(frame);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,6 @@
 | 
			
		|||
#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_seat.h>
 | 
			
		||||
#include <wlr/render/wlr_renderer.h>
 | 
			
		||||
#include "ext-image-copy-capture-v1-protocol.h"
 | 
			
		||||
#include "render/pixel_format.h"
 | 
			
		||||
 | 
			
		||||
#define IMAGE_COPY_CAPTURE_MANAGER_V1_VERSION 1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,65 +0,0 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <wayland-server-protocol.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include <wlr/types/wlr_fixes.h>
 | 
			
		||||
 | 
			
		||||
#define FIXES_VERSION 1
 | 
			
		||||
 | 
			
		||||
static void fixes_destroy(struct wl_client *client, struct wl_resource *resource) {
 | 
			
		||||
	wl_resource_destroy(resource);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void fixes_destroy_registry(struct wl_client *client, struct wl_resource *resource,
 | 
			
		||||
		struct wl_resource *registry) {
 | 
			
		||||
	wl_resource_destroy(registry);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct wl_fixes_interface fixes_impl = {
 | 
			
		||||
	.destroy = fixes_destroy,
 | 
			
		||||
	.destroy_registry = fixes_destroy_registry,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void fixes_bind(struct wl_client *wl_client, void *data, uint32_t version, uint32_t id) {
 | 
			
		||||
	struct wlr_fixes *fixes = data;
 | 
			
		||||
 | 
			
		||||
	struct wl_resource *resource = wl_resource_create(wl_client, &wl_fixes_interface, version, id);
 | 
			
		||||
	if (resource == NULL) {
 | 
			
		||||
		wl_client_post_no_memory(wl_client);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	wl_resource_set_implementation(resource, &fixes_impl, fixes, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void fixes_handle_display_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wlr_fixes *fixes = wl_container_of(listener, fixes, display_destroy);
 | 
			
		||||
	wl_signal_emit_mutable(&fixes->events.destroy, NULL);
 | 
			
		||||
 | 
			
		||||
	assert(wl_list_empty(&fixes->events.destroy.listener_list));
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&fixes->display_destroy.link);
 | 
			
		||||
	wl_global_destroy(fixes->global);
 | 
			
		||||
	free(fixes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct wlr_fixes *wlr_fixes_create(struct wl_display *display, uint32_t version) {
 | 
			
		||||
	assert(version <= FIXES_VERSION);
 | 
			
		||||
 | 
			
		||||
	struct wlr_fixes *fixes = calloc(1, sizeof(*fixes));
 | 
			
		||||
	if (fixes == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fixes->global = wl_global_create(display, &wl_fixes_interface, version, fixes, fixes_bind);
 | 
			
		||||
	if (fixes->global == NULL) {
 | 
			
		||||
		free(fixes);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_signal_init(&fixes->events.destroy);
 | 
			
		||||
 | 
			
		||||
	fixes->display_destroy.notify = fixes_handle_display_destroy;
 | 
			
		||||
	wl_display_add_destroy_listener(display, &fixes->display_destroy);
 | 
			
		||||
 | 
			
		||||
	return fixes;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -4,7 +4,6 @@
 | 
			
		|||
#include <unistd.h>
 | 
			
		||||
#include <wayland-server-core.h>
 | 
			
		||||
#include <wlr/interfaces/wlr_output.h>
 | 
			
		||||
#include <wlr/render/color.h>
 | 
			
		||||
#include <wlr/types/wlr_gamma_control_v1.h>
 | 
			
		||||
#include <wlr/types/wlr_output.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -157,9 +156,6 @@ static void gamma_control_manager_get_gamma_control(struct wl_client *client,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	size_t gamma_size = wlr_output_get_gamma_size(output);
 | 
			
		||||
	if (gamma_size == 0) {
 | 
			
		||||
		gamma_size = manager->fallback_gamma_size;
 | 
			
		||||
	}
 | 
			
		||||
	if (gamma_size == 0) {
 | 
			
		||||
		zwlr_gamma_control_v1_send_failed(resource);
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -265,31 +261,17 @@ struct wlr_gamma_control_v1 *wlr_gamma_control_manager_v1_get_control(
 | 
			
		|||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct wlr_color_transform *wlr_gamma_control_v1_get_color_transform(
 | 
			
		||||
		struct wlr_gamma_control_v1 *gamma_control) {
 | 
			
		||||
bool wlr_gamma_control_v1_apply(struct wlr_gamma_control_v1 *gamma_control,
 | 
			
		||||
		struct wlr_output_state *output_state) {
 | 
			
		||||
	if (gamma_control == NULL || gamma_control->table == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
		return wlr_output_state_set_gamma_lut(output_state, 0, NULL, NULL, NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const uint16_t *r = gamma_control->table;
 | 
			
		||||
	const uint16_t *g = gamma_control->table + gamma_control->ramp_size;
 | 
			
		||||
	const uint16_t *b = gamma_control->table + 2 * gamma_control->ramp_size;
 | 
			
		||||
 | 
			
		||||
	return wlr_color_transform_init_lut_3x1d(gamma_control->ramp_size, r, g, b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool wlr_gamma_control_v1_apply(struct wlr_gamma_control_v1 *gamma_control,
 | 
			
		||||
		struct wlr_output_state *output_state) {
 | 
			
		||||
	struct wlr_color_transform *tr = NULL;
 | 
			
		||||
	if (gamma_control != NULL && gamma_control->table != NULL) {
 | 
			
		||||
		tr = wlr_gamma_control_v1_get_color_transform(gamma_control);
 | 
			
		||||
		if (tr == NULL) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wlr_output_state_set_color_transform(output_state, tr);
 | 
			
		||||
	return true;
 | 
			
		||||
	return wlr_output_state_set_gamma_lut(output_state,
 | 
			
		||||
		gamma_control->ramp_size, r, g, b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wlr_gamma_control_v1_send_failed_and_destroy(struct wlr_gamma_control_v1 *gamma_control) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,7 +82,8 @@ static void notification_destroy(struct wlr_idle_notification_v1 *notification)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void notification_reset_timer(struct wlr_idle_notification_v1 *notification) {
 | 
			
		||||
	if (notification->notifier->inhibited && notification->obey_inhibitors) {
 | 
			
		||||
	if (notification->notifier->inhibited && 
 | 
			
		||||
			notification->obey_inhibitors) {
 | 
			
		||||
		notification_set_idle(notification, false);
 | 
			
		||||
		if (notification->timer != NULL) {
 | 
			
		||||
			wl_event_source_timer_update(notification->timer, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -190,8 +191,10 @@ static void notifier_handle_get_idle_notification(
 | 
			
		|||
 | 
			
		||||
static const struct ext_idle_notifier_v1_interface notifier_impl = {
 | 
			
		||||
	.destroy = resource_handle_destroy,
 | 
			
		||||
	.get_idle_notification = notifier_handle_get_idle_notification,
 | 
			
		||||
	.get_input_idle_notification = notifier_handle_get_input_idle_notification,
 | 
			
		||||
	.get_idle_notification = 
 | 
			
		||||
		notifier_handle_get_idle_notification,
 | 
			
		||||
	.get_input_idle_notification = 
 | 
			
		||||
		notifier_handle_get_input_idle_notification,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void notifier_bind(struct wl_client *client, void *data,
 | 
			
		||||
| 
						 | 
				
			
			@ -254,9 +257,12 @@ void wlr_idle_notifier_v1_set_inhibited(struct wlr_idle_notifier_v1 *notifier,
 | 
			
		|||
 | 
			
		||||
void wlr_idle_notifier_v1_notify_activity(struct wlr_idle_notifier_v1 *notifier,
 | 
			
		||||
		struct wlr_seat *seat) {
 | 
			
		||||
 | 
			
		||||
	struct wlr_idle_notification_v1 *notification;
 | 
			
		||||
	wl_list_for_each(notification, ¬ifier->notifications, link) {
 | 
			
		||||
		if (notification->seat == seat && !(notifier->inhibited && notification->obey_inhibitors)) {
 | 
			
		||||
		if (notification->seat == seat && 
 | 
			
		||||
			!(notifier->inhibited && 
 | 
			
		||||
				notification->obey_inhibitors)) {
 | 
			
		||||
			notification_handle_activity(notification);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,8 +56,7 @@ static void input_method_destroy(struct wlr_input_method_v2 *input_method) {
 | 
			
		|||
			popup_surface, tmp, &input_method->popup_surfaces, link) {
 | 
			
		||||
		popup_surface_destroy(popup_surface);
 | 
			
		||||
	}
 | 
			
		||||
	wlr_input_method_keyboard_grab_v2_destroy(input_method->keyboard_grab);
 | 
			
		||||
	wl_signal_emit_mutable(&input_method->events.destroy, NULL);
 | 
			
		||||
	wl_signal_emit_mutable(&input_method->events.destroy, input_method);
 | 
			
		||||
 | 
			
		||||
	assert(wl_list_empty(&input_method->events.commit.listener_list));
 | 
			
		||||
	assert(wl_list_empty(&input_method->events.new_popup_surface.listener_list));
 | 
			
		||||
| 
						 | 
				
			
			@ -66,6 +65,7 @@ static void input_method_destroy(struct wlr_input_method_v2 *input_method) {
 | 
			
		|||
 | 
			
		||||
	wl_list_remove(wl_resource_get_link(input_method->resource));
 | 
			
		||||
	wl_list_remove(&input_method->seat_client_destroy.link);
 | 
			
		||||
	wlr_input_method_keyboard_grab_v2_destroy(input_method->keyboard_grab);
 | 
			
		||||
	input_state_reset(&input_method->pending);
 | 
			
		||||
	input_state_reset(&input_method->current);
 | 
			
		||||
	free(input_method);
 | 
			
		||||
| 
						 | 
				
			
			@ -102,7 +102,7 @@ static void im_commit(struct wl_client *client, struct wl_resource *resource,
 | 
			
		|||
	input_method->current = input_method->pending;
 | 
			
		||||
	input_method->pending = (struct wlr_input_method_v2_state){0};
 | 
			
		||||
 | 
			
		||||
	wl_signal_emit_mutable(&input_method->events.commit, NULL);
 | 
			
		||||
	wl_signal_emit_mutable(&input_method->events.commit, input_method);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void im_commit_string(struct wl_client *client,
 | 
			
		||||
| 
						 | 
				
			
			@ -271,7 +271,8 @@ void wlr_input_method_keyboard_grab_v2_destroy(
 | 
			
		|||
	if (!keyboard_grab) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	wl_signal_emit_mutable(&keyboard_grab->events.destroy, NULL);
 | 
			
		||||
	wl_signal_emit_mutable(&keyboard_grab->events.destroy, keyboard_grab);
 | 
			
		||||
 | 
			
		||||
	assert(wl_list_empty(&keyboard_grab->events.destroy.listener_list));
 | 
			
		||||
 | 
			
		||||
	keyboard_grab->input_method->keyboard_grab = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -574,7 +575,7 @@ static void manager_get_input_method(struct wl_client *client,
 | 
			
		|||
	wl_resource_set_user_data(im_resource, input_method);
 | 
			
		||||
	wl_list_insert(&im_manager->input_methods,
 | 
			
		||||
		wl_resource_get_link(input_method->resource));
 | 
			
		||||
	wl_signal_emit_mutable(&im_manager->events.new_input_method, input_method);
 | 
			
		||||
	wl_signal_emit_mutable(&im_manager->events.input_method, input_method);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void manager_destroy(struct wl_client *client,
 | 
			
		||||
| 
						 | 
				
			
			@ -605,9 +606,9 @@ static void input_method_manager_bind(struct wl_client *wl_client, void *data,
 | 
			
		|||
static void handle_display_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wlr_input_method_manager_v2 *manager =
 | 
			
		||||
		wl_container_of(listener, manager, display_destroy);
 | 
			
		||||
	wl_signal_emit_mutable(&manager->events.destroy, NULL);
 | 
			
		||||
	wl_signal_emit_mutable(&manager->events.destroy, manager);
 | 
			
		||||
 | 
			
		||||
	assert(wl_list_empty(&manager->events.new_input_method.listener_list));
 | 
			
		||||
	assert(wl_list_empty(&manager->events.input_method.listener_list));
 | 
			
		||||
	assert(wl_list_empty(&manager->events.destroy.listener_list));
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&manager->display_destroy.link);
 | 
			
		||||
| 
						 | 
				
			
			@ -622,7 +623,7 @@ struct wlr_input_method_manager_v2 *wlr_input_method_manager_v2_create(
 | 
			
		|||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wl_signal_init(&im_manager->events.new_input_method);
 | 
			
		||||
	wl_signal_init(&im_manager->events.input_method);
 | 
			
		||||
	wl_signal_init(&im_manager->events.destroy);
 | 
			
		||||
 | 
			
		||||
	wl_list_init(&im_manager->input_methods);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -235,8 +235,6 @@ bool wlr_keyboard_set_keymap(struct wlr_keyboard *kb, struct xkb_keymap *keymap)
 | 
			
		|||
		XKB_LED_NAME_NUM,
 | 
			
		||||
		XKB_LED_NAME_CAPS,
 | 
			
		||||
		XKB_LED_NAME_SCROLL,
 | 
			
		||||
		XKB_LED_NAME_COMPOSE,
 | 
			
		||||
		XKB_LED_NAME_KANA,
 | 
			
		||||
	};
 | 
			
		||||
	for (size_t i = 0; i < WLR_LED_COUNT; ++i) {
 | 
			
		||||
		kb->led_indexes[i] = xkb_map_led_get_index(kb->keymap, led_names[i]);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ struct wlr_linux_drm_syncobj_surface_v1 {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
struct wlr_linux_drm_syncobj_surface_v1_commit {
 | 
			
		||||
	struct wlr_surface *surface;
 | 
			
		||||
	struct wlr_linux_drm_syncobj_surface_v1 *surface;
 | 
			
		||||
	struct wlr_drm_syncobj_timeline_waiter waiter;
 | 
			
		||||
	uint32_t cached_seq;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -192,7 +192,7 @@ static struct wlr_linux_drm_syncobj_surface_v1 *surface_from_wlr_surface(
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void surface_commit_destroy(struct wlr_linux_drm_syncobj_surface_v1_commit *commit) {
 | 
			
		||||
	wlr_surface_unlock_cached(commit->surface, commit->cached_seq);
 | 
			
		||||
	wlr_surface_unlock_cached(commit->surface->surface, commit->cached_seq);
 | 
			
		||||
	wl_list_remove(&commit->surface_destroy.link);
 | 
			
		||||
	wlr_drm_syncobj_timeline_waiter_finish(&commit->waiter);
 | 
			
		||||
	free(commit);
 | 
			
		||||
| 
						 | 
				
			
			@ -237,7 +237,7 @@ static bool lock_surface_commit(struct wlr_linux_drm_syncobj_surface_v1 *surface
 | 
			
		|||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	commit->surface = surface->surface;
 | 
			
		||||
	commit->surface = surface;
 | 
			
		||||
	commit->cached_seq = wlr_surface_lock_pending(surface->surface);
 | 
			
		||||
 | 
			
		||||
	commit->surface_destroy.notify = surface_commit_handle_surface_destroy;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,8 +9,6 @@
 | 
			
		|||
#include <wlr/util/box.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
 | 
			
		||||
#include "pointer-constraints-unstable-v1-protocol.h"
 | 
			
		||||
 | 
			
		||||
static const struct zwp_locked_pointer_v1_interface locked_pointer_impl;
 | 
			
		||||
static const struct zwp_confined_pointer_v1_interface confined_pointer_impl;
 | 
			
		||||
static const struct zwp_pointer_constraints_v1_interface pointer_constraints_impl;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -334,7 +334,7 @@ static void frame_handle_output_commit(struct wl_listener *listener,
 | 
			
		|||
 | 
			
		||||
	zwlr_screencopy_frame_v1_send_flags(frame->resource, 0);
 | 
			
		||||
	frame_send_damage(frame);
 | 
			
		||||
	frame_send_ready(frame, &event->when);
 | 
			
		||||
	frame_send_ready(frame, event->when);
 | 
			
		||||
	frame_destroy(frame);
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,7 +64,7 @@ void wlr_text_input_v3_send_done(struct wlr_text_input_v3 *text_input) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void wlr_text_input_destroy(struct wlr_text_input_v3 *text_input) {
 | 
			
		||||
	wl_signal_emit_mutable(&text_input->events.destroy, NULL);
 | 
			
		||||
	wl_signal_emit_mutable(&text_input->events.destroy, text_input);
 | 
			
		||||
 | 
			
		||||
	assert(wl_list_empty(&text_input->events.enable.listener_list));
 | 
			
		||||
	assert(wl_list_empty(&text_input->events.commit.listener_list));
 | 
			
		||||
| 
						 | 
				
			
			@ -192,12 +192,12 @@ static void text_input_commit(struct wl_client *client,
 | 
			
		|||
 | 
			
		||||
	if (!old_enabled && text_input->current_enabled) {
 | 
			
		||||
		text_input->active_features	= text_input->current.features;
 | 
			
		||||
		wl_signal_emit_mutable(&text_input->events.enable, NULL);
 | 
			
		||||
		wl_signal_emit_mutable(&text_input->events.enable, text_input);
 | 
			
		||||
	} else if (old_enabled && !text_input->current_enabled) {
 | 
			
		||||
		text_input->active_features	= 0;
 | 
			
		||||
		wl_signal_emit_mutable(&text_input->events.disable, NULL);
 | 
			
		||||
		wl_signal_emit_mutable(&text_input->events.disable, text_input);
 | 
			
		||||
	} else { // including never enabled
 | 
			
		||||
		wl_signal_emit_mutable(&text_input->events.commit, NULL);
 | 
			
		||||
		wl_signal_emit_mutable(&text_input->events.commit, text_input);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -287,7 +287,7 @@ static void text_input_manager_get_text_input(struct wl_client *client,
 | 
			
		|||
		text_input_manager_from_resource(resource);
 | 
			
		||||
	wl_list_insert(&manager->text_inputs, &text_input->link);
 | 
			
		||||
 | 
			
		||||
	wl_signal_emit_mutable(&manager->events.new_text_input, text_input);
 | 
			
		||||
	wl_signal_emit_mutable(&manager->events.text_input, text_input);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct zwp_text_input_manager_v3_interface
 | 
			
		||||
| 
						 | 
				
			
			@ -313,9 +313,9 @@ static void text_input_manager_bind(struct wl_client *wl_client, void *data,
 | 
			
		|||
static void handle_display_destroy(struct wl_listener *listener, void *data) {
 | 
			
		||||
	struct wlr_text_input_manager_v3 *manager =
 | 
			
		||||
		wl_container_of(listener, manager, display_destroy);
 | 
			
		||||
	wl_signal_emit_mutable(&manager->events.destroy, NULL);
 | 
			
		||||
	wl_signal_emit_mutable(&manager->events.destroy, manager);
 | 
			
		||||
 | 
			
		||||
	assert(wl_list_empty(&manager->events.new_text_input.listener_list));
 | 
			
		||||
	assert(wl_list_empty(&manager->events.text_input.listener_list));
 | 
			
		||||
	assert(wl_list_empty(&manager->events.destroy.listener_list));
 | 
			
		||||
 | 
			
		||||
	wl_list_remove(&manager->display_destroy.link);
 | 
			
		||||
| 
						 | 
				
			
			@ -332,7 +332,7 @@ struct wlr_text_input_manager_v3 *wlr_text_input_manager_v3_create(
 | 
			
		|||
 | 
			
		||||
	wl_list_init(&manager->text_inputs);
 | 
			
		||||
 | 
			
		||||
	wl_signal_init(&manager->events.new_text_input);
 | 
			
		||||
	wl_signal_init(&manager->events.text_input);
 | 
			
		||||
	wl_signal_init(&manager->events.destroy);
 | 
			
		||||
 | 
			
		||||
	manager->global = wl_global_create(display,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
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