backend/drm: Simplify object matching code
We originally used match_obj on planes, but this was largely unnecessary. Instead, this assigns planes statically at startup.
This commit is contained in:
		
							parent
							
								
									d80acadfd8
								
							
						
					
					
						commit
						b3f42548d0
					
				|  | @ -1,4 +1,4 @@ | |||
| #define _POSIX_C_SOURCE 200112L | ||||
| #define _XOPEN_SOURCE 700 | ||||
| #include <assert.h> | ||||
| #include <drm_fourcc.h> | ||||
| #include <drm_mode.h> | ||||
|  | @ -10,6 +10,7 @@ | |||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <strings.h> | ||||
| #include <time.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wayland-util.h> | ||||
|  | @ -72,11 +73,86 @@ bool check_drm_features(struct wlr_drm_backend *drm) { | |||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static int cmp_plane(const void *arg1, const void *arg2) { | ||||
| 	const struct wlr_drm_plane *a = arg1; | ||||
| 	const struct wlr_drm_plane *b = arg2; | ||||
| static bool add_plane(struct wlr_drm_backend *drm, | ||||
| 		struct wlr_drm_crtc *crtc, drmModePlane *drm_plane, | ||||
| 		uint32_t type, union wlr_drm_plane_props *props) { | ||||
| 	assert(!(type == DRM_PLANE_TYPE_PRIMARY && crtc->primary)); | ||||
| 
 | ||||
| 	return (int)a->type - (int)b->type; | ||||
| 	if (type == DRM_PLANE_TYPE_CURSOR && crtc->cursor) { | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	struct wlr_drm_plane *p = calloc(1, sizeof(*p)); | ||||
| 	if (!p) { | ||||
| 		wlr_log_errno(WLR_ERROR, "Allocation failed"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	p->type = type; | ||||
| 	p->id = drm_plane->plane_id; | ||||
| 	p->props = *props; | ||||
| 
 | ||||
| 	// Choose an RGB format for the plane
 | ||||
| 	uint32_t rgb_format = DRM_FORMAT_INVALID; | ||||
| 	for (size_t j = 0; j < drm_plane->count_formats; ++j) { | ||||
| 		uint32_t fmt = drm_plane->formats[j]; | ||||
| 		wlr_drm_format_set_add(&p->formats, fmt, DRM_FORMAT_MOD_INVALID); | ||||
| 
 | ||||
| 		if (fmt == DRM_FORMAT_ARGB8888) { | ||||
| 			// Prefer formats with alpha channel
 | ||||
| 			rgb_format = fmt; | ||||
| 			break; | ||||
| 		} else if (fmt == DRM_FORMAT_XRGB8888) { | ||||
| 			rgb_format = fmt; | ||||
| 		} | ||||
| 	} | ||||
| 	p->drm_format = rgb_format; | ||||
| 
 | ||||
| 	if (p->props.in_formats) { | ||||
| 		uint64_t blob_id; | ||||
| 		if (!get_drm_prop(drm->fd, p->id, p->props.in_formats, &blob_id)) { | ||||
| 			wlr_log(WLR_ERROR, "Failed to read IN_FORMATS property"); | ||||
| 			goto error; | ||||
| 		} | ||||
| 
 | ||||
| 		drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(drm->fd, blob_id); | ||||
| 		if (!blob) { | ||||
| 			wlr_log(WLR_ERROR, "Failed to read IN_FORMATS blob"); | ||||
| 			goto error; | ||||
| 		} | ||||
| 
 | ||||
| 		struct drm_format_modifier_blob *data = blob->data; | ||||
| 		uint32_t *fmts = (uint32_t *)((char *)data + data->formats_offset); | ||||
| 		struct drm_format_modifier *mods = (struct drm_format_modifier *) | ||||
| 			((char *)data + data->modifiers_offset); | ||||
| 		for (uint32_t i = 0; i < data->count_modifiers; ++i) { | ||||
| 			for (int j = 0; j < 64; ++j) { | ||||
| 				if (mods[i].formats & ((uint64_t)1 << j)) { | ||||
| 					wlr_drm_format_set_add(&p->formats, | ||||
| 						fmts[j + mods[i].offset], mods[i].modifier); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		drmModeFreePropertyBlob(blob); | ||||
| 	} | ||||
| 
 | ||||
| 	switch (type) { | ||||
| 	case DRM_PLANE_TYPE_PRIMARY: | ||||
| 		crtc->primary = p; | ||||
| 		break; | ||||
| 	case DRM_PLANE_TYPE_CURSOR: | ||||
| 		crtc->cursor = p; | ||||
| 		break; | ||||
| 	default: | ||||
| 		abort(); | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| 
 | ||||
| error: | ||||
| 	free(p); | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| static bool init_planes(struct wlr_drm_backend *drm) { | ||||
|  | @ -88,118 +164,72 @@ static bool init_planes(struct wlr_drm_backend *drm) { | |||
| 
 | ||||
| 	wlr_log(WLR_INFO, "Found %"PRIu32" DRM planes", plane_res->count_planes); | ||||
| 
 | ||||
| 	if (plane_res->count_planes == 0) { | ||||
| 		drmModeFreePlaneResources(plane_res); | ||||
| 		return true; | ||||
| 	} | ||||
| 	for (uint32_t i = 0; i < plane_res->count_planes; ++i) { | ||||
| 		uint32_t id = plane_res->planes[i]; | ||||
| 
 | ||||
| 	drm->num_planes = plane_res->count_planes; | ||||
| 	drm->planes = calloc(drm->num_planes, sizeof(*drm->planes)); | ||||
| 	if (!drm->planes) { | ||||
| 		wlr_log_errno(WLR_ERROR, "Allocation failed"); | ||||
| 		goto error_res; | ||||
| 	} | ||||
| 
 | ||||
| 	for (size_t i = 0; i < drm->num_planes; ++i) { | ||||
| 		struct wlr_drm_plane *p = &drm->planes[i]; | ||||
| 
 | ||||
| 		drmModePlane *plane = drmModeGetPlane(drm->fd, plane_res->planes[i]); | ||||
| 		drmModePlane *plane = drmModeGetPlane(drm->fd, id); | ||||
| 		if (!plane) { | ||||
| 			wlr_log_errno(WLR_ERROR, "Failed to get DRM plane"); | ||||
| 			goto error_planes; | ||||
| 			goto error; | ||||
| 		} | ||||
| 
 | ||||
| 		p->id = plane->plane_id; | ||||
| 		p->possible_crtcs = plane->possible_crtcs; | ||||
| 		union wlr_drm_plane_props props = {0}; | ||||
| 		if (!get_drm_plane_props(drm->fd, id, &props)) { | ||||
| 			drmModeFreePlane(plane); | ||||
| 			goto error; | ||||
| 		} | ||||
| 
 | ||||
| 		uint64_t type; | ||||
| 		if (!get_drm_plane_props(drm->fd, p->id, &p->props) || | ||||
| 				!get_drm_prop(drm->fd, p->id, p->props.type, &type)) { | ||||
| 		if (!get_drm_prop(drm->fd, id, props.type, &type)) { | ||||
| 			drmModeFreePlane(plane); | ||||
| 			goto error_planes; | ||||
| 			goto error; | ||||
| 		} | ||||
| 
 | ||||
| 		p->type = type; | ||||
| 		drm->num_type_planes[type]++; | ||||
| 		/*
 | ||||
| 		 * This is a very naive implementation of the plane matching | ||||
| 		 * logic. Primary and cursor planes should only work on a | ||||
| 		 * single CRTC, and this should be perfectly adequate, but | ||||
| 		 * overlay planes can potentially work with multiple CRTCs, | ||||
| 		 * meaning this could return inefficent/skewed results. | ||||
| 		 * | ||||
| 		 * However, we don't really care about overlay planes, as we | ||||
| 		 * don't support them yet. We only bother to keep basic | ||||
| 		 * tracking of them for DRM lease clients. | ||||
| 		 * | ||||
| 		 * possible_crtcs is a bitmask of crtcs, where each bit is an | ||||
| 		 * index into drmModeRes.crtcs. So if bit 0 is set (ffs starts | ||||
| 		 * counting from 1), crtc 0 is possible. | ||||
| 		 */ | ||||
| 		int crtc_bit = ffs(plane->possible_crtcs) - 1; | ||||
| 
 | ||||
| 		// Choose an RGB format for the plane
 | ||||
| 		uint32_t rgb_format = DRM_FORMAT_INVALID; | ||||
| 		for (size_t j = 0; j < plane->count_formats; ++j) { | ||||
| 			uint32_t fmt = plane->formats[j]; | ||||
| 			wlr_drm_format_set_add(&p->formats, fmt, DRM_FORMAT_MOD_INVALID); | ||||
| 		// This would be a kernel bug
 | ||||
| 		assert(crtc_bit >= 0 && (size_t)crtc_bit < drm->num_crtcs); | ||||
| 
 | ||||
| 			if (fmt == DRM_FORMAT_ARGB8888) { | ||||
| 				// Prefer formats with alpha channel
 | ||||
| 				rgb_format = fmt; | ||||
| 				break; | ||||
| 			} else if (fmt == DRM_FORMAT_XRGB8888) { | ||||
| 				rgb_format = fmt; | ||||
| 		struct wlr_drm_crtc *crtc = &drm->crtcs[crtc_bit]; | ||||
| 
 | ||||
| 		if (type == DRM_PLANE_TYPE_OVERLAY) { | ||||
| 			uint32_t *tmp = realloc(crtc->overlays, | ||||
| 				sizeof(*crtc->overlays) * (crtc->num_overlays + 1)); | ||||
| 			if (tmp) { | ||||
| 				crtc->overlays = tmp; | ||||
| 				crtc->overlays[crtc->num_overlays++] = id; | ||||
| 			} | ||||
| 		} | ||||
| 		// Some overlays exist which don't support XRGB8888/ARGB8888
 | ||||
| 		// We aren't even using overlay planes currently, so don't fail
 | ||||
| 		// on something unnecessary.
 | ||||
| 		if (type != DRM_PLANE_TYPE_OVERLAY && rgb_format == DRM_FORMAT_INVALID) { | ||||
| 			wlr_log(WLR_ERROR, "Failed to find an RGB format for plane %zu", i); | ||||
| 			drmModeFreePlane(plane); | ||||
| 			goto error_planes; | ||||
| 			continue; | ||||
| 		} | ||||
| 		p->drm_format = rgb_format; | ||||
| 
 | ||||
| 		if (p->props.in_formats) { | ||||
| 			uint64_t blob_id; | ||||
| 			if (!get_drm_prop(drm->fd, p->id, p->props.in_formats, &blob_id)) { | ||||
| 				wlr_log(WLR_ERROR, "Failed to read IN_FORMATS property"); | ||||
| 				drmModeFreePlane(plane); | ||||
| 				goto error_planes; | ||||
| 			} | ||||
| 
 | ||||
| 			drmModePropertyBlobRes *blob = | ||||
| 				drmModeGetPropertyBlob(drm->fd, blob_id); | ||||
| 			if (!blob) { | ||||
| 				wlr_log(WLR_ERROR, "Failed to read IN_FORMATS blob"); | ||||
| 				drmModeFreePlane(plane); | ||||
| 				goto error_planes; | ||||
| 			} | ||||
| 
 | ||||
| 			struct drm_format_modifier_blob *data = blob->data; | ||||
| 			uint32_t *fmts = (uint32_t *)((char *)data + data->formats_offset); | ||||
| 			struct drm_format_modifier *mods = (struct drm_format_modifier *) | ||||
| 				((char *)data + data->modifiers_offset); | ||||
| 			for (uint32_t i = 0; i < data->count_modifiers; ++i) { | ||||
| 				for (int j = 0; j < 64; ++j) { | ||||
| 					if (mods[i].formats & ((uint64_t)1 << j)) { | ||||
| 						wlr_drm_format_set_add(&p->formats, | ||||
| 							fmts[j + mods[i].offset], mods[i].modifier); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			drmModeFreePropertyBlob(blob); | ||||
| 		if (!add_plane(drm, crtc, plane, type, &props)) { | ||||
| 			drmModeFreePlane(plane); | ||||
| 			goto error; | ||||
| 		} | ||||
| 
 | ||||
| 		drmModeFreePlane(plane); | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_log(WLR_INFO, "(%zu overlay, %zu primary, %zu cursor)", | ||||
| 		drm->num_overlay_planes, | ||||
| 		drm->num_primary_planes, | ||||
| 		drm->num_cursor_planes); | ||||
| 
 | ||||
| 	qsort(drm->planes, drm->num_planes, sizeof(*drm->planes), cmp_plane); | ||||
| 
 | ||||
| 	drm->overlay_planes = drm->planes; | ||||
| 	drm->primary_planes = drm->overlay_planes | ||||
| 		+ drm->num_overlay_planes; | ||||
| 	drm->cursor_planes = drm->primary_planes | ||||
| 		+ drm->num_primary_planes; | ||||
| 
 | ||||
| 	drmModeFreePlaneResources(plane_res); | ||||
| 	return true; | ||||
| 
 | ||||
| error_planes: | ||||
| 	free(drm->planes); | ||||
| error_res: | ||||
| error: | ||||
| 	drmModeFreePlaneResources(plane_res); | ||||
| 	return false; | ||||
| } | ||||
|  | @ -252,26 +282,33 @@ void finish_drm_resources(struct wlr_drm_backend *drm) { | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	for (size_t i = 0; i < drm->num_planes; ++i) { | ||||
| 		struct wlr_drm_plane *p = &drm->planes[i]; | ||||
| 		wlr_drm_format_set_finish(&p->formats); | ||||
| 	} | ||||
| 
 | ||||
| 	for (size_t i = 0; i < drm->num_crtcs; ++i) { | ||||
| 		struct wlr_drm_crtc *crtc = &drm->crtcs[i]; | ||||
| 
 | ||||
| 		drmModeAtomicFree(crtc->atomic); | ||||
| 		drmModeFreeCrtc(crtc->legacy_crtc); | ||||
| 
 | ||||
| 		if (crtc->mode_id) { | ||||
| 			drmModeDestroyPropertyBlob(drm->fd, crtc->mode_id); | ||||
| 		} | ||||
| 		if (crtc->gamma_lut) { | ||||
| 			drmModeDestroyPropertyBlob(drm->fd, crtc->gamma_lut); | ||||
| 		} | ||||
| 
 | ||||
| 		free(crtc->gamma_table); | ||||
| 
 | ||||
| 		if (crtc->primary) { | ||||
| 			wlr_drm_format_set_finish(&crtc->primary->formats); | ||||
| 			free(crtc->primary); | ||||
| 		} | ||||
| 		if (crtc->cursor) { | ||||
| 			wlr_drm_format_set_finish(&crtc->cursor->formats); | ||||
| 			free(crtc->cursor); | ||||
| 		} | ||||
| 		free(crtc->overlays); | ||||
| 	} | ||||
| 
 | ||||
| 	free(drm->crtcs); | ||||
| 	free(drm->planes); | ||||
| } | ||||
| 
 | ||||
| static struct wlr_drm_connector *get_drm_connector_from_output( | ||||
|  | @ -477,7 +514,7 @@ static void drm_connector_start_renderer(struct wlr_drm_connector *conn) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs); | ||||
| static void realloc_crtcs(struct wlr_drm_backend *drm); | ||||
| 
 | ||||
| static void attempt_enable_needs_modeset(struct wlr_drm_backend *drm) { | ||||
| 	// Try to modeset any output that has a desired mode and a CRTC (ie. was
 | ||||
|  | @ -506,7 +543,7 @@ bool enable_drm_connector(struct wlr_output *output, bool enable) { | |||
| 
 | ||||
| 	if (enable && conn->crtc == NULL) { | ||||
| 		// Maybe we can steal a CRTC from a disabled output
 | ||||
| 		realloc_crtcs(drm, NULL); | ||||
| 		realloc_crtcs(drm); | ||||
| 	} | ||||
| 
 | ||||
| 	bool ok = drm->iface->conn_enable(drm, conn, enable); | ||||
|  | @ -517,7 +554,7 @@ bool enable_drm_connector(struct wlr_output *output, bool enable) { | |||
| 	if (enable) { | ||||
| 		drm_connector_start_renderer(conn); | ||||
| 	} else { | ||||
| 		realloc_crtcs(drm, NULL); | ||||
| 		realloc_crtcs(drm); | ||||
| 
 | ||||
| 		attempt_enable_needs_modeset(drm); | ||||
| 	} | ||||
|  | @ -526,82 +563,6 @@ bool enable_drm_connector(struct wlr_output *output, bool enable) { | |||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static ssize_t connector_index_from_crtc(struct wlr_drm_backend *drm, | ||||
| 		struct wlr_drm_crtc *crtc) { | ||||
| 	size_t i = 0; | ||||
| 	struct wlr_drm_connector *conn; | ||||
| 	wl_list_for_each(conn, &drm->outputs, link) { | ||||
| 		if (conn->crtc == crtc) { | ||||
| 			return i; | ||||
| 		} | ||||
| 		++i; | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| static void realloc_planes(struct wlr_drm_backend *drm, const uint32_t *crtc_in, | ||||
| 		bool *changed_outputs) { | ||||
| 	wlr_log(WLR_DEBUG, "Reallocating planes"); | ||||
| 
 | ||||
| 	// overlay, primary, cursor
 | ||||
| 	for (size_t type = 0; type < 3; ++type) { | ||||
| 		if (drm->num_type_planes[type] == 0) { | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		uint32_t possible[drm->num_type_planes[type] + 1]; | ||||
| 		uint32_t crtc[drm->num_crtcs + 1]; | ||||
| 		uint32_t crtc_res[drm->num_crtcs + 1]; | ||||
| 
 | ||||
| 		for (size_t i = 0; i < drm->num_type_planes[type]; ++i) { | ||||
| 			possible[i] = drm->type_planes[type][i].possible_crtcs; | ||||
| 		} | ||||
| 
 | ||||
| 		for (size_t i = 0; i < drm->num_crtcs; ++i) { | ||||
| 			if (crtc_in[i] == UNMATCHED) { | ||||
| 				crtc[i] = SKIP; | ||||
| 			} else if (drm->crtcs[i].planes[type]) { | ||||
| 				crtc[i] = drm->crtcs[i].planes[type] | ||||
| 					- drm->type_planes[type]; | ||||
| 			} else { | ||||
| 				crtc[i] = UNMATCHED; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		match_obj(drm->num_type_planes[type], possible, | ||||
| 			drm->num_crtcs, crtc, crtc_res); | ||||
| 
 | ||||
| 		for (size_t i = 0; i < drm->num_crtcs; ++i) { | ||||
| 			if (crtc_res[i] == UNMATCHED || crtc_res[i] == SKIP) { | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			struct wlr_drm_crtc *c = &drm->crtcs[i]; | ||||
| 			struct wlr_drm_plane **old = &c->planes[type]; | ||||
| 			struct wlr_drm_plane *new = &drm->type_planes[type][crtc_res[i]]; | ||||
| 
 | ||||
| 			if (*old != new) { | ||||
| 				wlr_log(WLR_DEBUG, | ||||
| 					"Assigning plane %d -> %d (type %zu) to CRTC %d", | ||||
| 					*old ? (int)(*old)->id : -1, | ||||
| 					new ? (int)new->id : -1, | ||||
| 					type, | ||||
| 					c->id); | ||||
| 
 | ||||
| 				ssize_t conn_idx = connector_index_from_crtc(drm, c); | ||||
| 				if (conn_idx >= 0) { | ||||
| 					changed_outputs[conn_idx] = true; | ||||
| 				} | ||||
| 				if (*old) { | ||||
| 					finish_drm_surface(&(*old)->surf); | ||||
| 				} | ||||
| 				finish_drm_surface(&new->surf); | ||||
| 				*old = new; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void drm_connector_cleanup(struct wlr_drm_connector *conn); | ||||
| 
 | ||||
| bool drm_connector_set_mode(struct wlr_output *output, | ||||
|  | @ -610,7 +571,7 @@ bool drm_connector_set_mode(struct wlr_output *output, | |||
| 	struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); | ||||
| 	if (conn->crtc == NULL) { | ||||
| 		// Maybe we can steal a CRTC from a disabled output
 | ||||
| 		realloc_crtcs(drm, NULL); | ||||
| 		realloc_crtcs(drm); | ||||
| 	} | ||||
| 	if (conn->crtc == NULL) { | ||||
| 		wlr_log(WLR_ERROR, "Cannot modeset '%s': no CRTC for this connector", | ||||
|  | @ -1001,51 +962,37 @@ static void dealloc_crtc(struct wlr_drm_connector *conn) { | |||
| 		conn->crtc - drm->crtcs, conn->output.name); | ||||
| 
 | ||||
| 	set_drm_connector_gamma(&conn->output, 0, NULL, NULL, NULL); | ||||
| 
 | ||||
| 	for (size_t type = 0; type < 3; ++type) { | ||||
| 		struct wlr_drm_plane *plane = conn->crtc->planes[type]; | ||||
| 		if (plane == NULL) { | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		finish_drm_surface(&plane->surf); | ||||
| 		conn->crtc->planes[type] = NULL; | ||||
| 	} | ||||
| 	finish_drm_surface(&conn->crtc->primary->surf); | ||||
| 	finish_drm_surface(&conn->crtc->cursor->surf); | ||||
| 
 | ||||
| 	drm->iface->conn_enable(drm, conn, false); | ||||
| 
 | ||||
| 	conn->crtc = NULL; | ||||
| } | ||||
| 
 | ||||
| static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs) { | ||||
| 	size_t num_outputs = wl_list_length(&drm->outputs); | ||||
| 	bool changed_local = changed_outputs ? false : true; | ||||
| static void realloc_crtcs(struct wlr_drm_backend *drm) { | ||||
| 	assert(drm->num_crtcs > 0); | ||||
| 
 | ||||
| 	if (changed_local) { | ||||
| 		changed_outputs = calloc(num_outputs, sizeof(bool)); | ||||
| 		if (changed_outputs == NULL) { | ||||
| 			wlr_log(WLR_ERROR, "Allocation failed"); | ||||
| 			return; | ||||
| 		} | ||||
| 	size_t num_outputs = wl_list_length(&drm->outputs); | ||||
| 	if (num_outputs == 0) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_log(WLR_DEBUG, "Reallocating CRTCs"); | ||||
| 
 | ||||
| 	uint32_t crtc[drm->num_crtcs + 1]; | ||||
| 	struct wlr_drm_connector *connectors[num_outputs]; | ||||
| 	uint32_t connector_constraints[num_outputs]; | ||||
| 	uint32_t previous_match[drm->num_crtcs]; | ||||
| 	uint32_t new_match[drm->num_crtcs]; | ||||
| 
 | ||||
| 	for (size_t i = 0; i < drm->num_crtcs; ++i) { | ||||
| 		crtc[i] = UNMATCHED; | ||||
| 		previous_match[i] = UNMATCHED; | ||||
| 	} | ||||
| 
 | ||||
| 	struct wlr_drm_connector *connectors[num_outputs + 1]; | ||||
| 
 | ||||
| 	uint32_t possible_crtc[num_outputs + 1]; | ||||
| 	memset(possible_crtc, 0, sizeof(possible_crtc)); | ||||
| 
 | ||||
| 	wlr_log(WLR_DEBUG, "State before reallocation:"); | ||||
| 	ssize_t i = -1; | ||||
| 	size_t i = 0; | ||||
| 	struct wlr_drm_connector *conn; | ||||
| 	wl_list_for_each(conn, &drm->outputs, link) { | ||||
| 		i++; | ||||
| 		connectors[i] = conn; | ||||
| 
 | ||||
| 		wlr_log(WLR_DEBUG, "  '%s' crtc=%d state=%d desired_enabled=%d", | ||||
|  | @ -1054,7 +1001,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs) { | |||
| 			conn->state, conn->desired_enabled); | ||||
| 
 | ||||
| 		if (conn->crtc) { | ||||
| 			crtc[conn->crtc - drm->crtcs] = i; | ||||
| 			previous_match[conn->crtc - drm->crtcs] = i; | ||||
| 		} | ||||
| 
 | ||||
| 		// Only search CRTCs for user-enabled outputs (that are already
 | ||||
|  | @ -1062,86 +1009,84 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs) { | |||
| 		if ((conn->state == WLR_DRM_CONN_CONNECTED || | ||||
| 				conn->state == WLR_DRM_CONN_NEEDS_MODESET) && | ||||
| 				conn->desired_enabled) { | ||||
| 			possible_crtc[i] = conn->possible_crtc; | ||||
| 			connector_constraints[i] = conn->possible_crtc; | ||||
| 		} else { | ||||
| 			// Will always fail to match anything
 | ||||
| 			connector_constraints[i] = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		++i; | ||||
| 	} | ||||
| 
 | ||||
| 	uint32_t crtc_res[drm->num_crtcs + 1]; | ||||
| 	match_obj(wl_list_length(&drm->outputs), possible_crtc, | ||||
| 		drm->num_crtcs, crtc, crtc_res); | ||||
| 	match_obj(num_outputs, connector_constraints, | ||||
| 		drm->num_crtcs, previous_match, new_match); | ||||
| 
 | ||||
| 	bool matched[num_outputs + 1]; | ||||
| 	memset(matched, false, sizeof(matched)); | ||||
| 	// Converts our crtc=>connector result into a connector=>crtc one.
 | ||||
| 	ssize_t connector_match[num_outputs]; | ||||
| 	for (size_t i = 0 ; i < num_outputs; ++i) { | ||||
| 		connector_match[i] = -1; | ||||
| 	} | ||||
| 	for (size_t i = 0; i < drm->num_crtcs; ++i) { | ||||
| 		if (crtc_res[i] != UNMATCHED) { | ||||
| 			matched[crtc_res[i]] = true; | ||||
| 		if (new_match[i] != UNMATCHED) { | ||||
| 			connector_match[new_match[i]] = i; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (size_t i = 0; i < drm->num_crtcs; ++i) { | ||||
| 		// We don't want any of the current monitors to be deactivated
 | ||||
| 		if (crtc[i] != UNMATCHED && !matched[crtc[i]] && | ||||
| 				connectors[crtc[i]]->desired_enabled) { | ||||
| 			wlr_log(WLR_DEBUG, "Could not match a CRTC for connected output %d", | ||||
| 				crtc[i]); | ||||
| 			goto free_changed_outputs; | ||||
| 	/*
 | ||||
| 	 * In the case that we add a new connector (hotplug) and we fail to | ||||
| 	 * match everything, we prefer to fail the new connector and keep all | ||||
| 	 * of the old mappings instead. | ||||
| 	 */ | ||||
| 	for (size_t i = 0; i < num_outputs; ++i) { | ||||
| 		struct wlr_drm_connector *conn = connectors[i]; | ||||
| 		if (conn->state == WLR_DRM_CONN_CONNECTED && | ||||
| 				conn->desired_enabled && | ||||
| 				connector_match[i] == -1) { | ||||
| 			wlr_log(WLR_DEBUG, "Could not match a CRTC for previously connected output; " | ||||
| 					"keeping old configuration"); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (size_t i = 0; i < drm->num_crtcs; ++i) { | ||||
| 		if (crtc_res[i] == crtc[i]) { | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		// De-allocate this CRTC on previous output
 | ||||
| 		if (crtc[i] != UNMATCHED) { | ||||
| 			changed_outputs[crtc[i]] = true; | ||||
| 			dealloc_crtc(connectors[crtc[i]]); | ||||
| 		} | ||||
| 
 | ||||
| 		// Assign this CRTC to next output
 | ||||
| 		if (crtc_res[i] != UNMATCHED) { | ||||
| 			changed_outputs[crtc_res[i]] = true; | ||||
| 
 | ||||
| 			struct wlr_drm_connector *conn = connectors[crtc_res[i]]; | ||||
| 			dealloc_crtc(conn); | ||||
| 			conn->crtc = &drm->crtcs[i]; | ||||
| 
 | ||||
| 			wlr_log(WLR_DEBUG, "Assigning CRTC %zu to output %d -> %d '%s'", | ||||
| 				i, crtc[i], crtc_res[i], conn->output.name); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_log(WLR_DEBUG, "State after reallocation:"); | ||||
| 	wl_list_for_each(conn, &drm->outputs, link) { | ||||
| 		wlr_log(WLR_DEBUG, "  '%s' crtc=%d state=%d desired_enabled=%d", | ||||
| 
 | ||||
| 	// Apply new configuration
 | ||||
| 	for (size_t i = 0; i < num_outputs; ++i) { | ||||
| 		struct wlr_drm_connector *conn = connectors[i]; | ||||
| 		bool prev_enabled = conn->crtc; | ||||
| 
 | ||||
| 		wlr_log(WLR_DEBUG, "  '%s' crtc=%zd state=%d desired_enabled=%d", | ||||
| 			conn->output.name, | ||||
| 			conn->crtc ? (int)(conn->crtc - drm->crtcs) : -1, | ||||
| 			connector_match[i], | ||||
| 			conn->state, conn->desired_enabled); | ||||
| 	} | ||||
| 
 | ||||
| 	realloc_planes(drm, crtc_res, changed_outputs); | ||||
| 		// We don't need to change anything.
 | ||||
| 		if (prev_enabled && connector_match[i] == conn->crtc - drm->crtcs) { | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		dealloc_crtc(conn); | ||||
| 
 | ||||
| 		if (connector_match[i] == -1) { | ||||
| 			if (prev_enabled) { | ||||
| 				wlr_log(WLR_DEBUG, "Output has %s lost its CRTC", | ||||
| 					conn->output.name); | ||||
| 				conn->state = WLR_DRM_CONN_NEEDS_MODESET; | ||||
| 				wlr_output_update_enabled(&conn->output, false); | ||||
| 				conn->desired_mode = conn->output.current_mode; | ||||
| 				wlr_output_update_mode(&conn->output, NULL); | ||||
| 			} | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		conn->crtc = &drm->crtcs[connector_match[i]]; | ||||
| 
 | ||||
| 		// Only realloc buffers if we have actually been modeset
 | ||||
| 		if (conn->state != WLR_DRM_CONN_CONNECTED) { | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 	// We need to reinitialize any plane that has changed
 | ||||
| 	i = -1; | ||||
| 	wl_list_for_each(conn, &drm->outputs, link) { | ||||
| 		i++; | ||||
| 		struct wlr_output_mode *mode = conn->output.current_mode; | ||||
| 
 | ||||
| 		if (conn->state != WLR_DRM_CONN_CONNECTED || !changed_outputs[i]) { | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (conn->crtc == NULL) { | ||||
| 			wlr_log(WLR_DEBUG, "Output has %s lost its CRTC", | ||||
| 				conn->output.name); | ||||
| 			conn->state = WLR_DRM_CONN_NEEDS_MODESET; | ||||
| 			wlr_output_update_enabled(&conn->output, false); | ||||
| 			conn->desired_mode = conn->output.current_mode; | ||||
| 			wlr_output_update_mode(&conn->output, NULL); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!init_drm_plane_surfaces(conn->crtc->primary, drm, | ||||
| 				mode->width, mode->height, drm->renderer.gbm_format)) { | ||||
| 			wlr_log(WLR_ERROR, "Failed to initialize renderer for plane"); | ||||
|  | @ -1153,11 +1098,6 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs) { | |||
| 
 | ||||
| 		wlr_output_damage_whole(&conn->output); | ||||
| 	} | ||||
| 
 | ||||
| free_changed_outputs: | ||||
| 	if (changed_local) { | ||||
| 		free(changed_outputs); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static uint32_t get_possible_crtcs(int fd, drmModeRes *res, | ||||
|  | @ -1392,25 +1332,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	bool changed_outputs[wl_list_length(&drm->outputs) + 1]; | ||||
| 	memset(changed_outputs, false, sizeof(changed_outputs)); | ||||
| 	for (size_t i = 0; i < new_outputs_len; ++i) { | ||||
| 		struct wlr_drm_connector *conn = new_outputs[i]; | ||||
| 
 | ||||
| 		ssize_t pos = -1; | ||||
| 		struct wlr_drm_connector *c; | ||||
| 		wl_list_for_each(c, &drm->outputs, link) { | ||||
| 			++pos; | ||||
| 			if (c == conn) { | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		assert(pos >= 0); | ||||
| 
 | ||||
| 		changed_outputs[pos] = true; | ||||
| 	} | ||||
| 
 | ||||
| 	realloc_crtcs(drm, changed_outputs); | ||||
| 	realloc_crtcs(drm); | ||||
| 
 | ||||
| 	for (size_t i = 0; i < new_outputs_len; ++i) { | ||||
| 		struct wlr_drm_connector *conn = new_outputs[i]; | ||||
|  | @ -1536,23 +1458,7 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) { | |||
| 
 | ||||
| 	switch (conn->state) { | ||||
| 	case WLR_DRM_CONN_CONNECTED: | ||||
| 	case WLR_DRM_CONN_CLEANUP:; | ||||
| 		struct wlr_drm_crtc *crtc = conn->crtc; | ||||
| 		if (crtc != NULL) { | ||||
| 			for (int i = 0; i < 3; ++i) { | ||||
| 				if (!crtc->planes[i]) { | ||||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
| 				finish_drm_surface(&crtc->planes[i]->surf); | ||||
| 				finish_drm_surface(&crtc->planes[i]->mgpu_surf); | ||||
| 				if (crtc->planes[i]->id == 0) { | ||||
| 					free(crtc->planes[i]); | ||||
| 					crtc->planes[i] = NULL; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	case WLR_DRM_CONN_CLEANUP: | ||||
| 		conn->output.current_mode = NULL; | ||||
| 		conn->desired_mode = NULL; | ||||
| 		struct wlr_drm_mode *mode, *tmp; | ||||
|  |  | |||
|  | @ -22,8 +22,6 @@ struct wlr_drm_plane { | |||
| 	uint32_t type; | ||||
| 	uint32_t id; | ||||
| 
 | ||||
| 	uint32_t possible_crtcs; | ||||
| 
 | ||||
| 	struct wlr_drm_surface surf; | ||||
| 	struct wlr_drm_surface mgpu_surf; | ||||
| 
 | ||||
|  | @ -49,14 +47,15 @@ struct wlr_drm_crtc { | |||
| 	// Legacy only
 | ||||
| 	drmModeCrtc *legacy_crtc; | ||||
| 
 | ||||
| 	union { | ||||
| 		struct { | ||||
| 			struct wlr_drm_plane *overlay; | ||||
| 			struct wlr_drm_plane *primary; | ||||
| 			struct wlr_drm_plane *cursor; | ||||
| 		}; | ||||
| 		struct wlr_drm_plane *planes[3]; | ||||
| 	}; | ||||
| 	struct wlr_drm_plane *primary; | ||||
| 	struct wlr_drm_plane *cursor; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * We don't support overlay planes yet, but we keep track of them to | ||||
| 	 * give to DRM lease clients. | ||||
| 	 */ | ||||
| 	size_t num_overlays; | ||||
| 	uint32_t *overlays; | ||||
| 
 | ||||
| 	union wlr_drm_crtc_props props; | ||||
| 
 | ||||
|  | @ -78,26 +77,6 @@ struct wlr_drm_backend { | |||
| 
 | ||||
| 	size_t num_crtcs; | ||||
| 	struct wlr_drm_crtc *crtcs; | ||||
| 	size_t num_planes; | ||||
| 	struct wlr_drm_plane *planes; | ||||
| 
 | ||||
| 	union { | ||||
| 		struct { | ||||
| 			size_t num_overlay_planes; | ||||
| 			size_t num_primary_planes; | ||||
| 			size_t num_cursor_planes; | ||||
| 		}; | ||||
| 		size_t num_type_planes[3]; | ||||
| 	}; | ||||
| 
 | ||||
| 	union { | ||||
| 		struct { | ||||
| 			struct wlr_drm_plane *overlay_planes; | ||||
| 			struct wlr_drm_plane *primary_planes; | ||||
| 			struct wlr_drm_plane *cursor_planes; | ||||
| 		}; | ||||
| 		struct wlr_drm_plane *type_planes[3]; | ||||
| 	}; | ||||
| 
 | ||||
| 	struct wl_display *display; | ||||
| 	struct wl_event_source *drm_event; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue