From: Hans de Goede Date: Tue, 27 Nov 2018 23:53:46 +0000 (+0100) Subject: drm: Pick a controller for unconfigured connectors X-Git-Tag: 0.9.5~82^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d67e729739f7cc3cb138bcad8182496c818bfd41;p=thirdparty%2Fplymouth.git drm: Pick a controller for unconfigured connectors So far we've been relying on the kernel fbcon code to set up all outputs, now that distros have started using deferred fbcon takeover for flickerfree booting, we can no longer rely on this and in some cases we must pick our own controllers. Signed-off-by: Hans de Goede --- diff --git a/src/plugins/renderers/drm/plugin.c b/src/plugins/renderers/drm/plugin.c index 87ecbfdc..20543eaa 100644 --- a/src/plugins/renderers/drm/plugin.c +++ b/src/plugins/renderers/drm/plugin.c @@ -980,7 +980,7 @@ close_device (ply_renderer_backend_t *backend) } static void -find_controller_for_output (ply_renderer_backend_t *backend, +output_get_controller_info (ply_renderer_backend_t *backend, ply_output_t *output) { int i; @@ -1092,12 +1092,119 @@ get_active_mode (ply_renderer_backend_t *backend, return mode; } +/* Some controllers can only drive some outputs, we want to find a combination + * where all (connected) outputs get a controller. To do this setup_outputs + * picks which output to assign a controller for first (trying all outputs), so + * that that one will get the first (free) controller and then recurses into + * itself to assign the remaining outputs. This tries assigning all remainig + * unassigned outputs first and returns the best result of all possible + * assignment orders for the remaining unassigned outputs. + * This repeats until we find an assignment order which results in a controller + * for all outputs, or we've tried all possible assignment orders. + */ + +static uint32_t +find_controller_for_output (ply_renderer_backend_t *backend, + const ply_output_t *outputs, + int outputs_len, + int output_idx) +{ + uint32_t possible_controllers = outputs[output_idx].possible_controllers; + int i, j; + + for (i = 0; i < backend->resources->count_crtcs; i++) { + uint32_t controller_id = backend->resources->crtcs[i]; + + if (!(possible_controllers & (1 << i))) + continue; /* controller not usable for this connector */ + + for (j = 0; j < outputs_len; j++) { + if (outputs[j].controller_id == controller_id) + break; + } + if (j < outputs_len) + continue; /* controller already in use */ + + return controller_id; + } + + return 0; +} + +static int +count_setup_controllers (const ply_output_t *outputs, + int outputs_len) +{ + int i, count = 0; + + for (i = 0; i < outputs_len; i++) { + if (outputs[i].controller_id) + count++; + } + + return count; +} + +static ply_output_t * +setup_outputs (ply_renderer_backend_t *backend, + const ply_output_t *outputs, + int outputs_len) +{ + const ply_output_t *best_outputs; + ply_output_t *new_outputs; + int i, count, best_count; + uint32_t controller_id; + + best_count = count_setup_controllers (outputs, outputs_len); + best_outputs = outputs; + + for (i = 0; i < outputs_len && best_count < outputs_len; i++) { + /* Already assigned? */ + if (outputs[i].controller_id) + continue; + + /* Assign controller for connector i */ + controller_id = find_controller_for_output (backend, outputs, outputs_len, i); + if (!controller_id) + continue; + + /* Add the new controller to a copy of the passed in connector + * template, we want to try all possible permutations of + * unassigned outputs without modifying the template. + */ + new_outputs = calloc (outputs_len, sizeof(*new_outputs)); + memcpy (new_outputs, outputs, outputs_len * sizeof(ply_output_t)); + new_outputs[i].controller_id = controller_id; + + /* Recurse into ourselves to assign remaining controllers, + * trying all possible assignment orders. + */ + new_outputs = setup_outputs (backend, new_outputs, outputs_len); + + count = count_setup_controllers (new_outputs, outputs_len); + if (count > best_count) { + if (best_outputs != outputs) + free ((void *)best_outputs); + best_outputs = new_outputs; + best_count = count; + } else { + free (new_outputs); + } + } + + if (best_outputs != outputs) + free ((void *)outputs); + + /* Our caller is allowed to modify outputs, cast-away the const */ + return (ply_output_t *)best_outputs; +} + static bool create_heads_for_active_connectors (ply_renderer_backend_t *backend) { ply_hashtable_t *heads_by_controller_id; ply_output_t *outputs; - int i, j, found, outputs_len; + int i, j, found, number_of_setup_outputs, outputs_len; heads_by_controller_id = ply_hashtable_new (NULL, NULL); @@ -1127,7 +1234,7 @@ create_heads_for_active_connectors (ply_renderer_backend_t *backend) outputs[found].connector = connector; - find_controller_for_output (backend, &outputs[found]); + output_get_controller_info (backend, &outputs[found]); ply_renderer_connector_get_rotation_and_tiled (backend, &outputs[found]); if (!outputs[found].tiled && backend->use_preferred_mode) @@ -1169,9 +1276,26 @@ create_heads_for_active_connectors (ply_renderer_backend_t *backend) } } - /* Step 3: TODO + /* Step 3: * Assign controllers to outputs without a controller */ + number_of_setup_outputs = count_setup_controllers (outputs, outputs_len); + if (number_of_setup_outputs != outputs_len) { + /* First try, try to assign controllers to outputs without one */ + ply_trace ("Some outputs don't have controllers, picking controllers"); + outputs = setup_outputs (backend, outputs, outputs_len); + number_of_setup_outputs = count_setup_controllers (outputs, outputs_len); + } + if (number_of_setup_outputs != outputs_len) { + /* Second try, re-assing controller for all outputs */ + ply_trace ("Some outputs still don't have controllers, re-assigning controllers for all outputs"); + for (i = 0; i < outputs_len; i++) + outputs[i].controller_id = 0; + outputs = setup_outputs (backend, outputs, outputs_len); + } + for (i = 0; i < outputs_len; i++) + ply_trace ("Using controller %u for connector %u", + outputs[i].controller_id, outputs[i].connector->connector_id); /* Step 4: * Create heads for all valid outputs