diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 77555aa2..2ebdbdc6 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1157,6 +1157,143 @@ static struct wlr_drm_crtc *connector_get_current_crtc( return NULL; } +static void connect_drm_connector(struct wlr_drm_connector *wlr_conn, + const drmModeConnector *drm_conn) { + struct wlr_drm_backend *drm = wlr_conn->backend; + + wlr_log(WLR_DEBUG, "Current CRTC: %d", + wlr_conn->crtc ? (int)wlr_conn->crtc->id : -1); + + wlr_output_init(&wlr_conn->output, &drm->backend, &output_impl, + drm->display); + + wlr_output_set_name(&wlr_conn->output, wlr_conn->name); + + wlr_conn->output.phys_width = drm_conn->mmWidth; + wlr_conn->output.phys_height = drm_conn->mmHeight; + wlr_log(WLR_INFO, "Physical size: %"PRId32"x%"PRId32, + wlr_conn->output.phys_width, wlr_conn->output.phys_height); + wlr_conn->output.subpixel = subpixel_map[drm_conn->subpixel]; + + get_drm_connector_props(drm->fd, wlr_conn->id, &wlr_conn->props); + + uint64_t non_desktop; + if (get_drm_prop(drm->fd, wlr_conn->id, + wlr_conn->props.non_desktop, &non_desktop)) { + if (non_desktop == 1) { + wlr_log(WLR_INFO, "Non-desktop connector"); + } + wlr_conn->output.non_desktop = non_desktop; + } + + wlr_conn->max_bpc = 0; + if (wlr_conn->props.max_bpc != 0) { + if (!introspect_drm_prop_range(drm->fd, wlr_conn->props.max_bpc, + NULL, &wlr_conn->max_bpc)) { + wlr_log(WLR_ERROR, "Failed to introspect 'max bpc' property"); + } + } + + size_t edid_len = 0; + uint8_t *edid = get_drm_prop_blob(drm->fd, + wlr_conn->id, wlr_conn->props.edid, &edid_len); + parse_edid(wlr_conn, edid_len, edid); + free(edid); + + char *subconnector = NULL; + if (wlr_conn->props.subconnector) { + subconnector = get_drm_prop_enum(drm->fd, + wlr_conn->id, wlr_conn->props.subconnector); + } + if (subconnector && strcmp(subconnector, "Native") == 0) { + free(subconnector); + subconnector = NULL; + } + + struct wlr_output *output = &wlr_conn->output; + char description[128]; + snprintf(description, sizeof(description), "%s %s%s%s (%s%s%s)", + output->make, output->model, + output->serial ? " " : "", + output->serial ? output->serial : "", + output->name, + subconnector ? " via " : "", + subconnector ? subconnector : ""); + wlr_output_set_description(output, description); + + free(subconnector); + + // Before iterating on the conn's modes, get the current KMS mode + // in use from the connector's CRTC. + drmModeModeInfo *current_modeinfo = NULL; + if (wlr_conn->crtc != NULL) { + if (wlr_conn->crtc->props.mode_id == 0) { + // Use the legacy drm interface. + if (wlr_conn->crtc->legacy_crtc->mode_valid) { + current_modeinfo = &wlr_conn->crtc->legacy_crtc->mode; + } + } else { + // Use the modern atomic drm interface. + size_t modeinfo_size = 0; + current_modeinfo = get_drm_prop_blob(drm->fd, wlr_conn->crtc->id, + wlr_conn->crtc->props.mode_id, &modeinfo_size); + assert(modeinfo_size == sizeof(drmModeModeInfo)); + } + } + + wlr_log(WLR_INFO, "Detected modes:"); + + for (int i = 0; i < drm_conn->count_modes; ++i) { + if (drm_conn->modes[i].flags & DRM_MODE_FLAG_INTERLACE) { + continue; + } + + struct wlr_drm_mode *mode = drm_mode_create(&drm_conn->modes[i]); + if (!mode) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + continue; + } + + // If this is the current mode set on the conn's crtc, + // then set it as the conn's output current mode. + if (current_modeinfo != NULL && memcmp(&mode->drm_mode, + current_modeinfo, sizeof(*current_modeinfo)) == 0) { + // Update width, height, refresh, transform_matrix and current_mode + // of this connector's output. + wlr_output_update_mode(&wlr_conn->output, &mode->wlr_mode); + + uint64_t mode_id = 0; + get_drm_prop(drm->fd, wlr_conn->crtc->id, + wlr_conn->crtc->props.mode_id, &mode_id); + + wlr_conn->crtc->mode_id = mode_id; + } + + wlr_log(WLR_INFO, " %"PRId32"x%"PRId32"@%"PRId32" %s", + mode->wlr_mode.width, mode->wlr_mode.height, + mode->wlr_mode.refresh, + mode->wlr_mode.preferred ? "(preferred)" : ""); + + wl_list_insert(wlr_conn->output.modes.prev, &mode->wlr_mode.link); + } + + if (wlr_conn->crtc != NULL && wlr_conn->crtc->props.mode_id != 0) { + // free() the modeinfo pointer, but only + // if not using the legacy API. + free(current_modeinfo); + } + + wlr_conn->possible_crtcs = + drmModeConnectorGetPossibleCrtcs(drm->fd, drm_conn); + if (wlr_conn->possible_crtcs == 0) { + wlr_drm_conn_log(wlr_conn, WLR_ERROR, "No CRTC possible"); + } + + wlr_output_update_enabled(&wlr_conn->output, wlr_conn->crtc != NULL); + + wlr_conn->status = DRM_MODE_CONNECTED; +} + static void disconnect_drm_connector(struct wlr_drm_connector *conn); void scan_drm_connectors(struct wlr_drm_backend *drm, @@ -1261,137 +1398,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm, if (wlr_conn->status == DRM_MODE_DISCONNECTED && drm_conn->connection == DRM_MODE_CONNECTED) { wlr_log(WLR_INFO, "'%s' connected", wlr_conn->name); - wlr_log(WLR_DEBUG, "Current CRTC: %d", - wlr_conn->crtc ? (int)wlr_conn->crtc->id : -1); - - wlr_output_init(&wlr_conn->output, &drm->backend, &output_impl, - drm->display); - - wlr_output_set_name(&wlr_conn->output, wlr_conn->name); - - wlr_conn->output.phys_width = drm_conn->mmWidth; - wlr_conn->output.phys_height = drm_conn->mmHeight; - wlr_log(WLR_INFO, "Physical size: %"PRId32"x%"PRId32, - wlr_conn->output.phys_width, wlr_conn->output.phys_height); - wlr_conn->output.subpixel = subpixel_map[drm_conn->subpixel]; - - get_drm_connector_props(drm->fd, wlr_conn->id, &wlr_conn->props); - - uint64_t non_desktop; - if (get_drm_prop(drm->fd, wlr_conn->id, - wlr_conn->props.non_desktop, &non_desktop)) { - if (non_desktop == 1) { - wlr_log(WLR_INFO, "Non-desktop connector"); - } - wlr_conn->output.non_desktop = non_desktop; - } - - wlr_conn->max_bpc = 0; - if (wlr_conn->props.max_bpc != 0) { - if (!introspect_drm_prop_range(drm->fd, wlr_conn->props.max_bpc, - NULL, &wlr_conn->max_bpc)) { - wlr_log(WLR_ERROR, "Failed to introspect 'max bpc' property"); - } - } - - size_t edid_len = 0; - uint8_t *edid = get_drm_prop_blob(drm->fd, - wlr_conn->id, wlr_conn->props.edid, &edid_len); - parse_edid(wlr_conn, edid_len, edid); - free(edid); - - char *subconnector = NULL; - if (wlr_conn->props.subconnector) { - subconnector = get_drm_prop_enum(drm->fd, - wlr_conn->id, wlr_conn->props.subconnector); - } - if (subconnector && strcmp(subconnector, "Native") == 0) { - free(subconnector); - subconnector = NULL; - } - - struct wlr_output *output = &wlr_conn->output; - char description[128]; - snprintf(description, sizeof(description), "%s %s%s%s (%s%s%s)", - output->make, output->model, - output->serial ? " " : "", - output->serial ? output->serial : "", - output->name, - subconnector ? " via " : "", - subconnector ? subconnector : ""); - wlr_output_set_description(output, description); - - free(subconnector); - - // Before iterating on the conn's modes, get the current KMS mode - // in use from the connector's CRTC. - drmModeModeInfo *current_modeinfo = NULL; - if (wlr_conn->crtc != NULL) { - if (wlr_conn->crtc->props.mode_id == 0) { - // Use the legacy drm interface. - if (wlr_conn->crtc->legacy_crtc->mode_valid) { - current_modeinfo = &wlr_conn->crtc->legacy_crtc->mode; - } - } else { - // Use the modern atomic drm interface. - size_t modeinfo_size = 0; - current_modeinfo = get_drm_prop_blob(drm->fd, wlr_conn->crtc->id, - wlr_conn->crtc->props.mode_id, &modeinfo_size); - assert(modeinfo_size == sizeof(drmModeModeInfo)); - } - } - - wlr_log(WLR_INFO, "Detected modes:"); - - for (int i = 0; i < drm_conn->count_modes; ++i) { - if (drm_conn->modes[i].flags & DRM_MODE_FLAG_INTERLACE) { - continue; - } - - struct wlr_drm_mode *mode = drm_mode_create(&drm_conn->modes[i]); - if (!mode) { - wlr_log_errno(WLR_ERROR, "Allocation failed"); - continue; - } - - // If this is the current mode set on the conn's crtc, - // then set it as the conn's output current mode. - if (current_modeinfo != NULL && memcmp(&mode->drm_mode, - current_modeinfo, sizeof(*current_modeinfo)) == 0) { - // Update width, height, refresh, transform_matrix and current_mode - // of this connector's output. - wlr_output_update_mode(&wlr_conn->output, &mode->wlr_mode); - - uint64_t mode_id = 0; - get_drm_prop(drm->fd, wlr_conn->crtc->id, - wlr_conn->crtc->props.mode_id, &mode_id); - - wlr_conn->crtc->mode_id = mode_id; - } - - wlr_log(WLR_INFO, " %"PRId32"x%"PRId32"@%"PRId32" %s", - mode->wlr_mode.width, mode->wlr_mode.height, - mode->wlr_mode.refresh, - mode->wlr_mode.preferred ? "(preferred)" : ""); - - wl_list_insert(wlr_conn->output.modes.prev, &mode->wlr_mode.link); - } - - if (wlr_conn->crtc != NULL && wlr_conn->crtc->props.mode_id != 0) { - // free() the modeinfo pointer, but only - // if not using the legacy API. - free(current_modeinfo); - } - - wlr_conn->possible_crtcs = - drmModeConnectorGetPossibleCrtcs(drm->fd, drm_conn); - if (wlr_conn->possible_crtcs == 0) { - wlr_drm_conn_log(wlr_conn, WLR_ERROR, "No CRTC possible"); - } - - wlr_output_update_enabled(&wlr_conn->output, wlr_conn->crtc != NULL); - - wlr_conn->status = DRM_MODE_CONNECTED; + connect_drm_connector(wlr_conn, drm_conn); new_outputs[new_outputs_len++] = wlr_conn; } else if (wlr_conn->status == DRM_MODE_CONNECTED && drm_conn->connection != DRM_MODE_CONNECTED) {