blob: 1f59923c73469d3cf4b71251efbbb00bfc46bfeb [file] [log] [blame]
Avi Drissman3e1a26c2022-09-15 20:26:031// Copyright 2014 The Chromium Authors
dnicoara9372a7912014-12-11 01:29:062// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Joone Hurd3ae8732018-04-17 18:05:095#include "ui/display/manager/configure_displays_task.h"
dnicoara9372a7912014-12-11 01:29:066
Gil Dekel788edb62020-11-25 23:41:287#include <cstddef>
Gil Dekelc8b8c4ed2022-05-04 20:30:388#include <string>
Gil Dekel788edb62020-11-25 23:41:289
Gil Dekel36b941dd2021-01-23 00:37:2310#include "base/containers/flat_set.h"
Avi Drissmanc149c162023-01-12 02:16:5911#include "base/functional/bind.h"
Hans Wennborg3930cf32020-06-17 16:29:5212#include "base/logging.h"
Daniele Castagna4f0689b2019-10-30 01:16:4713#include "base/metrics/histogram_functions.h"
Gil Dekel788edb62020-11-25 23:41:2814#include "base/metrics/histogram_macros.h"
Gil Dekelc8b8c4ed2022-05-04 20:30:3815#include "base/metrics/sparse_histogram.h"
Gil Dekel788edb62020-11-25 23:41:2816#include "base/numerics/safe_conversions.h"
Drew Davenport3e89c1b02024-05-09 22:12:0817#include "base/strings/string_number_conversions.h"
Gil Dekela6690b72023-05-02 18:59:0418#include "ui/display/manager/util/display_manager_util.h"
Mark Yacoubd18a2922020-07-07 01:14:1519#include "ui/display/types/display_configuration_params.h"
Gil Dekelbbc40352021-01-05 18:33:5620#include "ui/display/types/display_constants.h"
Gil Dekel36b941dd2021-01-23 00:37:2321#include "ui/display/types/display_mode.h"
dnicoara9372a7912014-12-11 01:29:0622#include "ui/display/types/display_snapshot.h"
23#include "ui/display/types/native_display_delegate.h"
24
kylechar7a067ec2017-01-07 01:16:2825namespace display {
dnicoara9372a7912014-12-11 01:29:0626
27namespace {
28
Gil Dekelc8b8c4ed2022-05-04 20:30:3829// The epsilon by which a refresh rate value may drift. For example:
30// 239.76Hz --> 240Hz. This value was chosen with the consideration of the
31// refresh rate value drifts presented in the "Video Formats—Video ID Code and
32// Aspect Ratios" table on p.40 of the CTA-861-G standard.
33constexpr float kRefreshRateEpsilon = 0.5f;
34
Gil Dekel788edb62020-11-25 23:41:2835// Because we do not offer hardware mirroring, the maximal number of external
36// displays that can be configured is limited by the number of available CRTCs,
37// which is usually three. Since the lifetime of the UMA using this value is one
38// year (exp. Nov. 2021), five buckets are more than enough for
39// its histogram (between 0 to 4 external monitors).
40constexpr int kMaxDisplaysCount = 5;
41
Gil Dekelc8b8c4ed2022-05-04 20:30:3842// Consolidates the UMA name prefix creation to one location, since it is used
43// in many different call-sites.
44const std::string GetUmaNamePrefixForRequest(
45 const DisplayConfigureRequest& request) {
46 return request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL
47 ? std::string("ConfigureDisplays.Internal.Modeset.")
48 : std::string("ConfigureDisplays.External.Modeset.");
49}
50
Gil Dekel66a97bc2022-04-29 04:21:5051// Find the next best mode that is smaller than |request->mode|. The next best
52// mode is found by comparing resolutions, and if those are similar, comparing
53// refresh rates. If no mode is found, return nullptr.
54const DisplayMode* FindNextMode(const DisplayConfigureRequest& request) {
55 DCHECK(request.mode);
Gil Dekelbbc40352021-01-05 18:33:5656
Gil Dekel66a97bc2022-04-29 04:21:5057 // Internal displays are restricted to their native mode. We do not
58 // attempt to downgrade their modes upon failure.
59 if (request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
dnicoaraa89c2082015-01-05 16:49:0660 return nullptr;
61
Gil Dekel66a97bc2022-04-29 04:21:5062 if (request.display->modes().size() <= 1)
63 return nullptr;
64
dnicoara9372a7912014-12-11 01:29:0665 const DisplayMode* best_mode = nullptr;
Gil Dekel66a97bc2022-04-29 04:21:5066 for (const auto& mode : request.display->modes()) {
67 if (*mode < *request.mode && (!best_mode || *mode > *best_mode))
dbasehore01e90042016-05-27 06:16:5168 best_mode = mode.get();
dnicoara9372a7912014-12-11 01:29:0669 }
70
71 return best_mode;
72}
73
Gil Dekelbbc40352021-01-05 18:33:5674void LogIfInvalidRequestForInternalDisplay(
75 const DisplayConfigureRequest& request) {
76 if (request.display->type() != DISPLAY_CONNECTION_TYPE_INTERNAL)
77 return;
78
79 if (request.mode == nullptr)
80 return;
81
82 if (request.mode == request.display->native_mode())
83 return;
84
85 LOG(ERROR) << "A mode other than the preferred mode was requested for the "
86 "internal display: preferred="
87 << request.display->native_mode()->ToString()
88 << " vs. requested=" << request.mode->ToString()
89 << ". Current mode="
90 << (request.display->current_mode()
91 ? request.display->current_mode()->ToString()
92 : "nullptr (disabled)")
93 << ".";
94}
95
Daniele Castagna4f0689b2019-10-30 01:16:4796// Samples used to define buckets used by DisplayResolution enum.
97// The enum is used to record screen resolution statistics.
98const int32_t kDisplayResolutionSamples[] = {1024, 1280, 1440, 1920,
99 2560, 3840, 5120, 7680};
100
Gil Dekelc8b8c4ed2022-05-04 20:30:38101void UpdateResolutionUma(const DisplayConfigureRequest& request,
102 const std::string& uma_name) {
103 // Display is powered off.
104 if (!request.mode)
105 return;
Daniele Castagna4f0689b2019-10-30 01:16:47106
Gil Dekelc8b8c4ed2022-05-04 20:30:38107 // First, compute the index of the enum DisplayResolution.
108 // The index has to match the definition of the enum in enums.xml.
109 const uint32_t samples_list_size = std::size(kDisplayResolutionSamples);
110 const gfx::Size size = request.mode->size();
Daniele Castagna4f0689b2019-10-30 01:16:47111 uint32_t width_idx = 0;
112 uint32_t height_idx = 0;
Gil Dekelc8b8c4ed2022-05-04 20:30:38113 for (; width_idx < samples_list_size; width_idx++) {
Daniele Castagna4f0689b2019-10-30 01:16:47114 if (size.width() <= kDisplayResolutionSamples[width_idx])
115 break;
116 }
Gil Dekelc8b8c4ed2022-05-04 20:30:38117 for (; height_idx < samples_list_size; height_idx++) {
Daniele Castagna4f0689b2019-10-30 01:16:47118 if (size.height() <= kDisplayResolutionSamples[height_idx])
119 break;
120 }
121
Gil Dekelc8b8c4ed2022-05-04 20:30:38122 int display_resolution_index = 0;
123 if (width_idx == samples_list_size || height_idx == samples_list_size) {
124 // Check if we are in the overflow bucket.
125 display_resolution_index = samples_list_size * samples_list_size + 1;
126 } else {
127 // Compute the index of DisplayResolution, starting from 1, since 0 is used
128 // when powering off the display.
129 display_resolution_index = width_idx * samples_list_size + height_idx + 1;
130 }
131
132 base::UmaHistogramExactLinear(uma_name, display_resolution_index,
133 samples_list_size * samples_list_size + 2);
Daniele Castagna4f0689b2019-10-30 01:16:47134}
135
Gil Dekelc8b8c4ed2022-05-04 20:30:38136// A list of common refresh rates that are used to help fit approximate refresh
137// rate values into one of the common refresh rate bins.
138constexpr float kCommonDisplayRefreshRates[] = {
139 24.0, 25.0, 30.0, 45.0, 48.0, 50.0, 60.0, 75.0,
140 90.0, 100.0, 120.0, 144.0, 165.0, 200.0, 240.0};
Gil Dekel20dc5302020-12-01 20:03:41141
Gil Dekelc8b8c4ed2022-05-04 20:30:38142void UpdateRefreshRateUma(const DisplayConfigureRequest& request,
143 const std::string& uma_name) {
144 // Display is powered off.
145 if (!request.mode)
146 return;
Gil Dekel20dc5302020-12-01 20:03:41147
Gil Dekelc8b8c4ed2022-05-04 20:30:38148 base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
149 uma_name, base::HistogramBase::kUmaTargetedHistogramFlag);
150
151 // Check if the refresh value is within an epsilon from one of the common
152 // refresh rate values.
Gil Dekela7ca9fc2022-05-16 19:25:37153 for (float common_rate : kCommonDisplayRefreshRates) {
154 const bool is_within_epsilon = std::abs(request.mode->refresh_rate() -
155 common_rate) < kRefreshRateEpsilon;
Gil Dekelc8b8c4ed2022-05-04 20:30:38156 if (is_within_epsilon) {
Gil Dekela7ca9fc2022-05-16 19:25:37157 histogram->Add(common_rate);
Gil Dekelc8b8c4ed2022-05-04 20:30:38158 return;
159 }
160 }
161
162 // Since this is not a common refresh rate value, report it as is.
163 histogram->Add(request.mode->refresh_rate());
Gil Dekel20dc5302020-12-01 20:03:41164}
165
Gil Dekel36b941dd2021-01-23 00:37:23166void UpdateAttemptSucceededUma(
167 const std::vector<DisplayConfigureRequest>& requests,
168 bool display_success) {
169 for (const auto& request : requests) {
Gil Dekelc8b8c4ed2022-05-04 20:30:38170 const std::string uma_name_prefix = GetUmaNamePrefixForRequest(request);
171 base::UmaHistogramBoolean(uma_name_prefix + "AttemptSucceeded",
172 display_success);
Gil Dekel36b941dd2021-01-23 00:37:23173
174 VLOG(2) << "Configured status=" << display_success
175 << " display=" << request.display->display_id()
176 << " origin=" << request.origin.ToString()
Andrew Wolfers4eb4c302023-02-14 21:37:33177 << " mode=" << (request.mode ? request.mode->ToString() : "null")
178 << " enable_vrr=" << request.enable_vrr;
Gil Dekel36b941dd2021-01-23 00:37:23179 }
Gil Dekel20dc5302020-12-01 20:03:41180}
181
Gil Dekel36b941dd2021-01-23 00:37:23182void UpdateFinalStatusUma(
Gil Dekel81fc8d52023-07-26 19:40:47183 const std::vector<RequestAndStatusList>& requests_and_statuses,
184 ConfigureDisplaysTask::Status status) {
Gil Dekel20dc5302020-12-01 20:03:41185 int mst_external_displays = 0;
Gil Dekel36b941dd2021-01-23 00:37:23186 size_t total_external_displays = requests_and_statuses.size();
187 for (auto& request_and_status : requests_and_statuses) {
Gil Dekel472925e2022-05-16 18:55:27188 const DisplayConfigureRequest* request = request_and_status.first;
Gil Dekel36b941dd2021-01-23 00:37:23189
Gil Dekel20dc5302020-12-01 20:03:41190 // Is this display SST (single-stream vs. MST multi-stream).
Gil Dekel472925e2022-05-16 18:55:27191 const bool sst_display = request->display->base_connector_id() &&
192 request->display->path_topology().empty();
Gil Dekel20dc5302020-12-01 20:03:41193 if (!sst_display)
194 mst_external_displays++;
195
Gil Dekel472925e2022-05-16 18:55:27196 if (request->display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
Gil Dekel20dc5302020-12-01 20:03:41197 total_external_displays--;
198
Gil Dekel472925e2022-05-16 18:55:27199 const std::string uma_name_prefix = GetUmaNamePrefixForRequest(*request);
Gil Dekelc8b8c4ed2022-05-04 20:30:38200 if (request_and_status.second) {
Gil Dekel472925e2022-05-16 18:55:27201 UpdateResolutionUma(*request, uma_name_prefix + "Success.Resolution");
202 UpdateRefreshRateUma(*request, uma_name_prefix + "Success.RefreshRate");
Gil Dekelc8b8c4ed2022-05-04 20:30:38203 }
204 base::UmaHistogramBoolean(uma_name_prefix + "FinalStatus",
205 request_and_status.second);
Gil Dekel20dc5302020-12-01 20:03:41206 }
207
Gil Dekel81fc8d52023-07-26 19:40:47208 base::UmaHistogramEnumeration("ConfigureDisplays.Modeset.FinalTaskStatus",
209 status);
210
Gil Dekel20dc5302020-12-01 20:03:41211 base::UmaHistogramExactLinear(
212 "ConfigureDisplays.Modeset.TotalExternalDisplaysCount",
213 base::checked_cast<int>(total_external_displays), kMaxDisplaysCount);
214
215 base::UmaHistogramExactLinear(
216 "ConfigureDisplays.Modeset.MstExternalDisplaysCount",
217 mst_external_displays, kMaxDisplaysCount);
218
219 if (total_external_displays > 0) {
220 const int mst_displays_percentage =
221 100.0 * mst_external_displays / total_external_displays;
222 UMA_HISTOGRAM_PERCENTAGE(
223 "ConfigureDisplays.Modeset.MstExternalDisplaysPercentage",
224 mst_displays_percentage);
225 }
226}
227
Drew Davenport3e89c1b02024-05-09 22:12:08228// After a successful configuration, the DisplaySnapshot associated with a
229// request needs to have its state updated to reflect the new configuration.
230void UpdateSnapshotAfterConfiguration(const DisplayConfigureRequest& request) {
231 request.display->set_current_mode(request.mode);
232 request.display->set_origin(request.origin);
233 if (request.display->IsVrrCapable()) {
234 request.display->set_variable_refresh_rate_state(
235 request.enable_vrr ? display::kVrrEnabled : display::kVrrDisabled);
236 }
237}
238
dnicoara9372a7912014-12-11 01:29:06239} // namespace
240
241DisplayConfigureRequest::DisplayConfigureRequest(DisplaySnapshot* display,
242 const DisplayMode* mode,
Andrew Wolfers4eb4c302023-02-14 21:37:33243 const gfx::Point& origin,
244 bool enable_vrr)
245 : display(display), mode(mode), origin(origin), enable_vrr(enable_vrr) {}
246
247DisplayConfigureRequest::DisplayConfigureRequest(DisplaySnapshot* display,
248 const DisplayMode* mode,
dnicoara9372a7912014-12-11 01:29:06249 const gfx::Point& origin)
Drew Davenport3e89c1b02024-05-09 22:12:08250 : DisplayConfigureRequest(display,
251 mode,
252 origin,
253 /*enable_vrr=*/false) {}
dnicoara9372a7912014-12-11 01:29:06254
255ConfigureDisplaysTask::ConfigureDisplaysTask(
256 NativeDisplayDelegate* delegate,
257 const std::vector<DisplayConfigureRequest>& requests,
Drew Davenport7636a462022-07-21 20:14:30258 ResponseCallback callback,
259 ConfigurationType configuration_type)
dnicoara9372a7912014-12-11 01:29:06260 : delegate_(delegate),
261 requests_(requests),
Drew Davenport7636a462022-07-21 20:14:30262 configuration_type_(configuration_type),
Sylvain Defresne23395c7a2019-10-02 10:07:45263 callback_(std::move(callback)),
Jeremy Roman47d432e2019-08-20 14:24:00264 task_status_(SUCCESS) {
afakhry4e92e8c2017-04-20 17:04:59265 delegate_->AddObserver(this);
dnicoara9372a7912014-12-11 01:29:06266}
267
Gil Dekel472925e2022-05-16 18:55:27268ConfigureDisplaysTask::RequestToOriginalMode::RequestToOriginalMode(
269 DisplayConfigureRequest* request,
270 const DisplayMode* original_mode)
271 : request(request), original_mode(original_mode) {}
272
afakhry4e92e8c2017-04-20 17:04:59273ConfigureDisplaysTask::~ConfigureDisplaysTask() {
274 delegate_->RemoveObserver(this);
275}
dnicoara9372a7912014-12-11 01:29:06276
277void ConfigureDisplaysTask::Run() {
Gil Dekel3369eec2020-10-06 19:53:10278 DCHECK(!requests_.empty());
dnicoara9372a7912014-12-11 01:29:06279
Gil Dekelc8b8c4ed2022-05-04 20:30:38280 const bool is_first_attempt = pending_display_group_requests_.empty();
Gil Dekel3369eec2020-10-06 19:53:10281 std::vector<display::DisplayConfigurationParams> config_requests;
282 for (const auto& request : requests_) {
Gil Dekelbbc40352021-01-05 18:33:56283 LogIfInvalidRequestForInternalDisplay(request);
284
Gil Dekel3369eec2020-10-06 19:53:10285 config_requests.emplace_back(request.display->display_id(), request.origin,
Andrew Wolfers4eb4c302023-02-14 21:37:33286 request.mode, request.enable_vrr);
Daniele Castagna4f0689b2019-10-30 01:16:47287
Gil Dekelc8b8c4ed2022-05-04 20:30:38288 if (is_first_attempt) {
289 const std::string uma_name_prefix = GetUmaNamePrefixForRequest(request);
290 UpdateResolutionUma(request,
291 uma_name_prefix + "OriginalRequest.Resolution");
292 }
dnicoara9372a7912014-12-11 01:29:06293 }
294
Gil Dekel36b941dd2021-01-23 00:37:23295 const auto& on_configured =
Gil Dekelc8b8c4ed2022-05-04 20:30:38296 is_first_attempt ? &ConfigureDisplaysTask::OnFirstAttemptConfigured
297 : &ConfigureDisplaysTask::OnRetryConfigured;
Gil Dekel36b941dd2021-01-23 00:37:23298
Drew Davenport5686c952024-03-08 16:47:50299 display::ModesetFlags modeset_flags{display::ModesetFlag::kTestModeset};
Drew Davenport7636a462022-07-21 20:14:30300 if (configuration_type_ == kConfigurationTypeSeamless)
Drew Davenport5686c952024-03-08 16:47:50301 modeset_flags.Put(display::ModesetFlag::kSeamlessModeset);
Gil Dekel36b941dd2021-01-23 00:37:23302 delegate_->Configure(
303 config_requests,
Gil Dekelcd4c2c02022-07-19 18:01:37304 base::BindOnce(on_configured, weak_ptr_factory_.GetWeakPtr()),
Drew Davenport7636a462022-07-21 20:14:30305 modeset_flags);
dnicoara9372a7912014-12-11 01:29:06306}
307
afakhry4e92e8c2017-04-20 17:04:59308void ConfigureDisplaysTask::OnConfigurationChanged() {}
309
310void ConfigureDisplaysTask::OnDisplaySnapshotsInvalidated() {
afakhry4e92e8c2017-04-20 17:04:59311 // From now on, don't access |requests_[index]->display|; they're invalid.
312 task_status_ = ERROR;
313 weak_ptr_factory_.InvalidateWeakPtrs();
Gil Dekel3369eec2020-10-06 19:53:10314 std::move(callback_).Run(task_status_);
afakhry4e92e8c2017-04-20 17:04:59315}
316
Gil Dekel36b941dd2021-01-23 00:37:23317void ConfigureDisplaysTask::OnFirstAttemptConfigured(bool config_success) {
318 UpdateAttemptSucceededUma(requests_, config_success);
Daniele Castagna4f0689b2019-10-30 01:16:47319
Gil Dekel36b941dd2021-01-23 00:37:23320 if (!config_success) {
Gil Dekel472925e2022-05-16 18:55:27321 // Partition |requests_| into smaller groups via
322 // |pending_display_group_requests_|, update the task's state, and initiate
323 // the retry logic. The next time |delegate_|->Configure() terminates
324 // OnRetryConfigured() will be executed instead.
Gil Dekel36b941dd2021-01-23 00:37:23325 PartitionRequests();
326 DCHECK(!pending_display_group_requests_.empty());
Gil Dekel472925e2022-05-16 18:55:27327 // Prep the first group
328 for (const auto& pair : pending_display_group_requests_.front())
329 pair.request->mode = pair.original_mode;
Gil Dekel42f7aba2021-01-08 18:59:55330 task_status_ = PARTIAL_SUCCESS;
331 Run();
332 return;
dnicoara9372a7912014-12-11 01:29:06333 }
334
Gil Dekel36b941dd2021-01-23 00:37:23335 // This code execute only when the first modeset attempt fully succeeds.
Gil Dekel8f7fa0182022-07-22 17:45:14336 // Submit the current |requests_| for modeset.
337 std::vector<display::DisplayConfigurationParams> config_requests;
338 for (const auto& request : requests_) {
339 final_requests_status_.emplace_back(&request, true);
340
341 config_requests.emplace_back(request.display->display_id(), request.origin,
Andrew Wolfers4eb4c302023-02-14 21:37:33342 request.mode, request.enable_vrr);
Gil Dekel36b941dd2021-01-23 00:37:23343 }
Gil Dekel788edb62020-11-25 23:41:28344
Drew Davenport5686c952024-03-08 16:47:50345 display::ModesetFlags modeset_flags{display::ModesetFlag::kCommitModeset};
Gil Dekel8f7fa0182022-07-22 17:45:14346 if (configuration_type_ == kConfigurationTypeSeamless)
Drew Davenport5686c952024-03-08 16:47:50347 modeset_flags.Put(display::ModesetFlag::kSeamlessModeset);
Gil Dekel8f7fa0182022-07-22 17:45:14348 delegate_->Configure(config_requests,
349 base::BindOnce(&ConfigureDisplaysTask::OnConfigured,
350 weak_ptr_factory_.GetWeakPtr()),
351 modeset_flags);
dnicoara9372a7912014-12-11 01:29:06352}
353
Gil Dekel36b941dd2021-01-23 00:37:23354void ConfigureDisplaysTask::OnRetryConfigured(bool config_success) {
355 UpdateAttemptSucceededUma(requests_, config_success);
356
357 if (!config_success) {
358 // If one of the largest display request can be downgraded, try again.
359 // Otherwise this configuration task is a failure.
Gil Dekel472925e2022-05-16 18:55:27360 if (DowngradeDisplayRequestGroup()) {
Gil Dekel36b941dd2021-01-23 00:37:23361 Run();
362 return;
363 } else {
Gil Dekel472925e2022-05-16 18:55:27364 // Disable all displays in the current group, since we failed to find an
365 // alternative mode. Note that we skip modeset if the latest (or a
366 // single) pending group fails. There is no point in disabling displays
367 // that are already disabled from previous attempts and failed to change
368 // mode.
369 for (const auto& pair : pending_display_group_requests_.front())
370 pair.request->mode = nullptr;
Gil Dekel36b941dd2021-01-23 00:37:23371 task_status_ = ERROR;
372 }
Gil Dekel8f7fa0182022-07-22 17:45:14373 } else {
374 // This configuration attempt passed test-modeset. Cache it so we can use it
375 // to modeset the displays once we are done testing, or if no other future
376 // attempts succeed.
377 last_successful_config_parameters_.clear();
378 for (const auto& request : requests_) {
379 last_successful_config_parameters_.emplace_back(
Andrew Wolfers4eb4c302023-02-14 21:37:33380 request.display->display_id(), request.origin, request.mode,
381 request.enable_vrr);
Gil Dekel8f7fa0182022-07-22 17:45:14382 }
Gil Dekel36b941dd2021-01-23 00:37:23383 }
384
385 // This code executes only when this display group request fully succeeds or
386 // fails to modeset. Update the final status of this group.
Gil Dekel8f7fa0182022-07-22 17:45:14387 for (const auto& pair : pending_display_group_requests_.front())
388 final_requests_status_.emplace_back(pair.request, config_success);
Gil Dekel36b941dd2021-01-23 00:37:23389
390 // Subsequent modeset attempts will be done on the next pending display group,
391 // if one exists.
392 pending_display_group_requests_.pop();
Gil Dekel36b941dd2021-01-23 00:37:23393 if (!pending_display_group_requests_.empty()) {
Gil Dekel472925e2022-05-16 18:55:27394 // Prep the next group
395 for (const auto& pair : pending_display_group_requests_.front())
396 pair.request->mode = pair.original_mode;
Gil Dekel36b941dd2021-01-23 00:37:23397 Run();
398 return;
399 }
400
Gil Dekel8f7fa0182022-07-22 17:45:14401 if (task_status_ == ERROR) {
402 LOG(WARNING) << "One or more of the connected display groups failed to "
403 "pass test-modeset entirely and will be disabled.";
404
405 if (last_successful_config_parameters_.empty()) {
406 LOG(ERROR) << "Display configuration failed. No modeset was attempted.";
407
Gil Dekel81fc8d52023-07-26 19:40:47408 UpdateFinalStatusUma(final_requests_status_, task_status_);
Gil Dekel8f7fa0182022-07-22 17:45:14409 std::move(callback_).Run(task_status_);
410 return;
411 }
412 }
413
414 // Configure the displays using the last successful configuration parameter
415 // list.
Drew Davenport5686c952024-03-08 16:47:50416 display::ModesetFlags modeset_flags{display::ModesetFlag::kCommitModeset};
Gil Dekel8f7fa0182022-07-22 17:45:14417 if (configuration_type_ == kConfigurationTypeSeamless)
Drew Davenport5686c952024-03-08 16:47:50418 modeset_flags.Put(display::ModesetFlag::kSeamlessModeset);
Gil Dekel8f7fa0182022-07-22 17:45:14419 delegate_->Configure(last_successful_config_parameters_,
420 base::BindOnce(&ConfigureDisplaysTask::OnConfigured,
421 weak_ptr_factory_.GetWeakPtr()),
422 modeset_flags);
423}
424
425void ConfigureDisplaysTask::OnConfigured(bool config_success) {
426 if (config_success) {
427 for (const DisplayConfigureRequest& request : requests_) {
Drew Davenport3e89c1b02024-05-09 22:12:08428 UpdateSnapshotAfterConfiguration(request);
Gil Dekel8f7fa0182022-07-22 17:45:14429 }
430 }
431
Gil Dekel81fc8d52023-07-26 19:40:47432 UpdateFinalStatusUma(final_requests_status_, task_status_);
Gil Dekel36b941dd2021-01-23 00:37:23433 std::move(callback_).Run(task_status_);
434}
435
436void ConfigureDisplaysTask::PartitionRequests() {
437 pending_display_group_requests_ = PartitionedRequestsQueue();
Gil Dekel36b941dd2021-01-23 00:37:23438
Mark Yacoub100f2df2022-04-19 18:01:14439 base::flat_set<uint64_t> handled_connectors;
Gil Dekel36b941dd2021-01-23 00:37:23440 for (size_t i = 0; i < requests_.size(); ++i) {
441 uint64_t connector_id = requests_[i].display->base_connector_id();
442 if (handled_connectors.find(connector_id) != handled_connectors.end())
443 continue;
444
Gil Dekel472925e2022-05-16 18:55:27445 std::vector<ConfigureDisplaysTask::RequestToOriginalMode> request_group;
Gil Dekel36b941dd2021-01-23 00:37:23446 for (size_t j = i; j < requests_.size(); ++j) {
Gil Dekel472925e2022-05-16 18:55:27447 if (connector_id == requests_[j].display->base_connector_id()) {
448 // Disable all requests in preparation increment connector retries after
449 // mapping them to their original request.
450 request_group.emplace_back(&requests_[j], requests_[j].mode);
451 requests_[j].mode = nullptr;
452 }
Gil Dekel36b941dd2021-01-23 00:37:23453 }
454
Gil Dekel36b941dd2021-01-23 00:37:23455 handled_connectors.insert(connector_id);
Mark Yacoub100f2df2022-04-19 18:01:14456 pending_display_group_requests_.push(request_group);
Gil Dekel36b941dd2021-01-23 00:37:23457 }
458}
459
Gil Dekel472925e2022-05-16 18:55:27460bool ConfigureDisplaysTask::DowngradeDisplayRequestGroup() {
Gil Dekel36b941dd2021-01-23 00:37:23461 auto cmp = [](DisplayConfigureRequest* lhs, DisplayConfigureRequest* rhs) {
462 return *lhs->mode < *rhs->mode;
463 };
464 std::priority_queue<DisplayConfigureRequest*,
465 std::vector<DisplayConfigureRequest*>, decltype(cmp)>
466 sorted_requests(cmp);
467
Gil Dekel472925e2022-05-16 18:55:27468 for (const auto& pair : pending_display_group_requests_.front()) {
469 if (pair.request->display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
Gil Dekel36b941dd2021-01-23 00:37:23470 continue;
471
Gil Dekel472925e2022-05-16 18:55:27472 if (!pair.request->mode)
Gil Dekel36b941dd2021-01-23 00:37:23473 continue;
474
Gil Dekel472925e2022-05-16 18:55:27475 sorted_requests.push(pair.request);
Gil Dekel36b941dd2021-01-23 00:37:23476 }
477
478 // Fail if there are no viable candidates to downgrade
479 if (sorted_requests.empty())
480 return false;
481
482 while (!sorted_requests.empty()) {
483 DisplayConfigureRequest* next_request = sorted_requests.top();
484 sorted_requests.pop();
485
Gil Dekel66a97bc2022-04-29 04:21:50486 const DisplayMode* next_mode = FindNextMode(*next_request);
Gil Dekel36b941dd2021-01-23 00:37:23487 if (next_mode) {
488 next_request->mode = next_mode;
489 return true;
490 }
491 }
492
493 return false;
494}
495
kylechar7a067ec2017-01-07 01:16:28496} // namespace display