mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-11-03 09:01:40 -05:00 
			
		
		
		
	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
					
				
					 2 changed files with 227 additions and 342 deletions
				
			
		| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#define _POSIX_C_SOURCE 200112L
 | 
					#define _XOPEN_SOURCE 700
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <drm_fourcc.h>
 | 
					#include <drm_fourcc.h>
 | 
				
			||||||
#include <drm_mode.h>
 | 
					#include <drm_mode.h>
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <strings.h>
 | 
				
			||||||
#include <time.h>
 | 
					#include <time.h>
 | 
				
			||||||
#include <wayland-server.h>
 | 
					#include <wayland-server.h>
 | 
				
			||||||
#include <wayland-util.h>
 | 
					#include <wayland-util.h>
 | 
				
			||||||
| 
						 | 
					@ -72,11 +73,86 @@ bool check_drm_features(struct wlr_drm_backend *drm) {
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int cmp_plane(const void *arg1, const void *arg2) {
 | 
					static bool add_plane(struct wlr_drm_backend *drm,
 | 
				
			||||||
	const struct wlr_drm_plane *a = arg1;
 | 
							struct wlr_drm_crtc *crtc, drmModePlane *drm_plane,
 | 
				
			||||||
	const struct wlr_drm_plane *b = arg2;
 | 
							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) {
 | 
					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);
 | 
						wlr_log(WLR_INFO, "Found %"PRIu32" DRM planes", plane_res->count_planes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (plane_res->count_planes == 0) {
 | 
						for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
 | 
				
			||||||
		drmModeFreePlaneResources(plane_res);
 | 
							uint32_t id = plane_res->planes[i];
 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm->num_planes = plane_res->count_planes;
 | 
							drmModePlane *plane = drmModeGetPlane(drm->fd, id);
 | 
				
			||||||
	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]);
 | 
					 | 
				
			||||||
		if (!plane) {
 | 
							if (!plane) {
 | 
				
			||||||
			wlr_log_errno(WLR_ERROR, "Failed to get DRM plane");
 | 
								wlr_log_errno(WLR_ERROR, "Failed to get DRM plane");
 | 
				
			||||||
			goto error_planes;
 | 
								goto error;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		p->id = plane->plane_id;
 | 
							union wlr_drm_plane_props props = {0};
 | 
				
			||||||
		p->possible_crtcs = plane->possible_crtcs;
 | 
							if (!get_drm_plane_props(drm->fd, id, &props)) {
 | 
				
			||||||
 | 
								drmModeFreePlane(plane);
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint64_t type;
 | 
							uint64_t type;
 | 
				
			||||||
		if (!get_drm_plane_props(drm->fd, p->id, &p->props) ||
 | 
							if (!get_drm_prop(drm->fd, id, props.type, &type)) {
 | 
				
			||||||
				!get_drm_prop(drm->fd, p->id, p->props.type, &type)) {
 | 
					 | 
				
			||||||
			drmModeFreePlane(plane);
 | 
								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
 | 
							// This would be a kernel bug
 | 
				
			||||||
		uint32_t rgb_format = DRM_FORMAT_INVALID;
 | 
							assert(crtc_bit >= 0 && (size_t)crtc_bit < drm->num_crtcs);
 | 
				
			||||||
		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);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (fmt == DRM_FORMAT_ARGB8888) {
 | 
							struct wlr_drm_crtc *crtc = &drm->crtcs[crtc_bit];
 | 
				
			||||||
				// Prefer formats with alpha channel
 | 
					
 | 
				
			||||||
				rgb_format = fmt;
 | 
							if (type == DRM_PLANE_TYPE_OVERLAY) {
 | 
				
			||||||
				break;
 | 
								uint32_t *tmp = realloc(crtc->overlays,
 | 
				
			||||||
			} else if (fmt == DRM_FORMAT_XRGB8888) {
 | 
									sizeof(*crtc->overlays) * (crtc->num_overlays + 1));
 | 
				
			||||||
				rgb_format = fmt;
 | 
								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);
 | 
								drmModeFreePlane(plane);
 | 
				
			||||||
			goto error_planes;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		p->drm_format = rgb_format;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (p->props.in_formats) {
 | 
							if (!add_plane(drm, crtc, plane, type, &props)) {
 | 
				
			||||||
			uint64_t blob_id;
 | 
								drmModeFreePlane(plane);
 | 
				
			||||||
			if (!get_drm_prop(drm->fd, p->id, p->props.in_formats, &blob_id)) {
 | 
								goto error;
 | 
				
			||||||
				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);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		drmModeFreePlane(plane);
 | 
							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);
 | 
						drmModeFreePlaneResources(plane_res);
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
error_planes:
 | 
					error:
 | 
				
			||||||
	free(drm->planes);
 | 
					 | 
				
			||||||
error_res:
 | 
					 | 
				
			||||||
	drmModeFreePlaneResources(plane_res);
 | 
						drmModeFreePlaneResources(plane_res);
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -252,26 +282,33 @@ void finish_drm_resources(struct wlr_drm_backend *drm) {
 | 
				
			||||||
		return;
 | 
							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) {
 | 
						for (size_t i = 0; i < drm->num_crtcs; ++i) {
 | 
				
			||||||
		struct wlr_drm_crtc *crtc = &drm->crtcs[i];
 | 
							struct wlr_drm_crtc *crtc = &drm->crtcs[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		drmModeAtomicFree(crtc->atomic);
 | 
							drmModeAtomicFree(crtc->atomic);
 | 
				
			||||||
		drmModeFreeCrtc(crtc->legacy_crtc);
 | 
							drmModeFreeCrtc(crtc->legacy_crtc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (crtc->mode_id) {
 | 
							if (crtc->mode_id) {
 | 
				
			||||||
			drmModeDestroyPropertyBlob(drm->fd, crtc->mode_id);
 | 
								drmModeDestroyPropertyBlob(drm->fd, crtc->mode_id);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (crtc->gamma_lut) {
 | 
							if (crtc->gamma_lut) {
 | 
				
			||||||
			drmModeDestroyPropertyBlob(drm->fd, crtc->gamma_lut);
 | 
								drmModeDestroyPropertyBlob(drm->fd, crtc->gamma_lut);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		free(crtc->gamma_table);
 | 
							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->crtcs);
 | 
				
			||||||
	free(drm->planes);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct wlr_drm_connector *get_drm_connector_from_output(
 | 
					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) {
 | 
					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
 | 
						// 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) {
 | 
						if (enable && conn->crtc == NULL) {
 | 
				
			||||||
		// Maybe we can steal a CRTC from a disabled output
 | 
							// 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);
 | 
						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) {
 | 
						if (enable) {
 | 
				
			||||||
		drm_connector_start_renderer(conn);
 | 
							drm_connector_start_renderer(conn);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		realloc_crtcs(drm, NULL);
 | 
							realloc_crtcs(drm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		attempt_enable_needs_modeset(drm);
 | 
							attempt_enable_needs_modeset(drm);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -526,82 +563,6 @@ bool enable_drm_connector(struct wlr_output *output, bool enable) {
 | 
				
			||||||
	return true;
 | 
						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);
 | 
					static void drm_connector_cleanup(struct wlr_drm_connector *conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool drm_connector_set_mode(struct wlr_output *output,
 | 
					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);
 | 
						struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
 | 
				
			||||||
	if (conn->crtc == NULL) {
 | 
						if (conn->crtc == NULL) {
 | 
				
			||||||
		// Maybe we can steal a CRTC from a disabled output
 | 
							// Maybe we can steal a CRTC from a disabled output
 | 
				
			||||||
		realloc_crtcs(drm, NULL);
 | 
							realloc_crtcs(drm);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (conn->crtc == NULL) {
 | 
						if (conn->crtc == NULL) {
 | 
				
			||||||
		wlr_log(WLR_ERROR, "Cannot modeset '%s': no CRTC for this connector",
 | 
							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);
 | 
							conn->crtc - drm->crtcs, conn->output.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_drm_connector_gamma(&conn->output, 0, NULL, NULL, NULL);
 | 
						set_drm_connector_gamma(&conn->output, 0, NULL, NULL, NULL);
 | 
				
			||||||
 | 
						finish_drm_surface(&conn->crtc->primary->surf);
 | 
				
			||||||
	for (size_t type = 0; type < 3; ++type) {
 | 
						finish_drm_surface(&conn->crtc->cursor->surf);
 | 
				
			||||||
		struct wlr_drm_plane *plane = conn->crtc->planes[type];
 | 
					 | 
				
			||||||
		if (plane == NULL) {
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		finish_drm_surface(&plane->surf);
 | 
					 | 
				
			||||||
		conn->crtc->planes[type] = NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm->iface->conn_enable(drm, conn, false);
 | 
						drm->iface->conn_enable(drm, conn, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn->crtc = NULL;
 | 
						conn->crtc = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs) {
 | 
					static void realloc_crtcs(struct wlr_drm_backend *drm) {
 | 
				
			||||||
	size_t num_outputs = wl_list_length(&drm->outputs);
 | 
						assert(drm->num_crtcs > 0);
 | 
				
			||||||
	bool changed_local = changed_outputs ? false : true;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (changed_local) {
 | 
						size_t num_outputs = wl_list_length(&drm->outputs);
 | 
				
			||||||
		changed_outputs = calloc(num_outputs, sizeof(bool));
 | 
						if (num_outputs == 0) {
 | 
				
			||||||
		if (changed_outputs == NULL) {
 | 
							return;
 | 
				
			||||||
			wlr_log(WLR_ERROR, "Allocation failed");
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_log(WLR_DEBUG, "Reallocating CRTCs");
 | 
						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) {
 | 
						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:");
 | 
						wlr_log(WLR_DEBUG, "State before reallocation:");
 | 
				
			||||||
	ssize_t i = -1;
 | 
						size_t i = 0;
 | 
				
			||||||
	struct wlr_drm_connector *conn;
 | 
						struct wlr_drm_connector *conn;
 | 
				
			||||||
	wl_list_for_each(conn, &drm->outputs, link) {
 | 
						wl_list_for_each(conn, &drm->outputs, link) {
 | 
				
			||||||
		i++;
 | 
					 | 
				
			||||||
		connectors[i] = conn;
 | 
							connectors[i] = conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		wlr_log(WLR_DEBUG, "  '%s' crtc=%d state=%d desired_enabled=%d",
 | 
							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);
 | 
								conn->state, conn->desired_enabled);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (conn->crtc) {
 | 
							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
 | 
							// 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 ||
 | 
							if ((conn->state == WLR_DRM_CONN_CONNECTED ||
 | 
				
			||||||
				conn->state == WLR_DRM_CONN_NEEDS_MODESET) &&
 | 
									conn->state == WLR_DRM_CONN_NEEDS_MODESET) &&
 | 
				
			||||||
				conn->desired_enabled) {
 | 
									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(num_outputs, connector_constraints,
 | 
				
			||||||
	match_obj(wl_list_length(&drm->outputs), possible_crtc,
 | 
							drm->num_crtcs, previous_match, new_match);
 | 
				
			||||||
		drm->num_crtcs, crtc, crtc_res);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool matched[num_outputs + 1];
 | 
						// Converts our crtc=>connector result into a connector=>crtc one.
 | 
				
			||||||
	memset(matched, false, sizeof(matched));
 | 
						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) {
 | 
						for (size_t i = 0; i < drm->num_crtcs; ++i) {
 | 
				
			||||||
		if (crtc_res[i] != UNMATCHED) {
 | 
							if (new_match[i] != UNMATCHED) {
 | 
				
			||||||
			matched[crtc_res[i]] = true;
 | 
								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
 | 
						 * In the case that we add a new connector (hotplug) and we fail to
 | 
				
			||||||
		if (crtc[i] != UNMATCHED && !matched[crtc[i]] &&
 | 
						 * match everything, we prefer to fail the new connector and keep all
 | 
				
			||||||
				connectors[crtc[i]]->desired_enabled) {
 | 
						 * of the old mappings instead.
 | 
				
			||||||
			wlr_log(WLR_DEBUG, "Could not match a CRTC for connected output %d",
 | 
						 */
 | 
				
			||||||
				crtc[i]);
 | 
						for (size_t i = 0; i < num_outputs; ++i) {
 | 
				
			||||||
			goto free_changed_outputs;
 | 
							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:");
 | 
						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->output.name,
 | 
				
			||||||
			conn->crtc ? (int)(conn->crtc - drm->crtcs) : -1,
 | 
								connector_match[i],
 | 
				
			||||||
			conn->state, conn->desired_enabled);
 | 
								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;
 | 
							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,
 | 
							if (!init_drm_plane_surfaces(conn->crtc->primary, drm,
 | 
				
			||||||
				mode->width, mode->height, drm->renderer.gbm_format)) {
 | 
									mode->width, mode->height, drm->renderer.gbm_format)) {
 | 
				
			||||||
			wlr_log(WLR_ERROR, "Failed to initialize renderer for plane");
 | 
								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);
 | 
							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,
 | 
					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];
 | 
						realloc_crtcs(drm);
 | 
				
			||||||
	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);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (size_t i = 0; i < new_outputs_len; ++i) {
 | 
						for (size_t i = 0; i < new_outputs_len; ++i) {
 | 
				
			||||||
		struct wlr_drm_connector *conn = new_outputs[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) {
 | 
						switch (conn->state) {
 | 
				
			||||||
	case WLR_DRM_CONN_CONNECTED:
 | 
						case WLR_DRM_CONN_CONNECTED:
 | 
				
			||||||
	case WLR_DRM_CONN_CLEANUP:;
 | 
						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;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		conn->output.current_mode = NULL;
 | 
							conn->output.current_mode = NULL;
 | 
				
			||||||
		conn->desired_mode = NULL;
 | 
							conn->desired_mode = NULL;
 | 
				
			||||||
		struct wlr_drm_mode *mode, *tmp;
 | 
							struct wlr_drm_mode *mode, *tmp;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,8 +22,6 @@ struct wlr_drm_plane {
 | 
				
			||||||
	uint32_t type;
 | 
						uint32_t type;
 | 
				
			||||||
	uint32_t id;
 | 
						uint32_t id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t possible_crtcs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct wlr_drm_surface surf;
 | 
						struct wlr_drm_surface surf;
 | 
				
			||||||
	struct wlr_drm_surface mgpu_surf;
 | 
						struct wlr_drm_surface mgpu_surf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,14 +47,15 @@ struct wlr_drm_crtc {
 | 
				
			||||||
	// Legacy only
 | 
						// Legacy only
 | 
				
			||||||
	drmModeCrtc *legacy_crtc;
 | 
						drmModeCrtc *legacy_crtc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	union {
 | 
						struct wlr_drm_plane *primary;
 | 
				
			||||||
		struct {
 | 
						struct wlr_drm_plane *cursor;
 | 
				
			||||||
			struct wlr_drm_plane *overlay;
 | 
					
 | 
				
			||||||
			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.
 | 
				
			||||||
		struct wlr_drm_plane *planes[3];
 | 
						 */
 | 
				
			||||||
	};
 | 
						size_t num_overlays;
 | 
				
			||||||
 | 
						uint32_t *overlays;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	union wlr_drm_crtc_props props;
 | 
						union wlr_drm_crtc_props props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,26 +77,6 @@ struct wlr_drm_backend {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size_t num_crtcs;
 | 
						size_t num_crtcs;
 | 
				
			||||||
	struct wlr_drm_crtc *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_display *display;
 | 
				
			||||||
	struct wl_event_source *drm_event;
 | 
						struct wl_event_source *drm_event;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue