blob: fa3841c409a625e9069b8e37f06595612ed5e377 [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"
Gil Dekela6690b72023-05-02 18:59:0417#include "ui/display/manager/util/display_manager_util.h"
Mark Yacoubd18a2922020-07-07 01:14:1518#include "ui/display/types/display_configuration_params.h"
Gil Dekelbbc40352021-01-05 18:33:5619#include "ui/display/types/display_constants.h"
Gil Dekel36b941dd2021-01-23 00:37:2320#include "ui/display/types/display_mode.h"
dnicoara9372a7912014-12-11 01:29:0621#include "ui/display/types/display_snapshot.h"
22#include "ui/display/types/native_display_delegate.h"
23
kylechar7a067ec2017-01-07 01:16:2824namespace display {
dnicoara9372a7912014-12-11 01:29:0625
26namespace {
27
Gil Dekelc8b8c4ed2022-05-04 20:30:3828// The epsilon by which a refresh rate value may drift. For example:
29// 239.76Hz --> 240Hz. This value was chosen with the consideration of the
30// refresh rate value drifts presented in the "Video Formats—Video ID Code and
31// Aspect Ratios" table on p.40 of the CTA-861-G standard.
32constexpr float kRefreshRateEpsilon = 0.5f;
33
Gil Dekel788edb62020-11-25 23:41:2834// Because we do not offer hardware mirroring, the maximal number of external
35// displays that can be configured is limited by the number of available CRTCs,
36// which is usually three. Since the lifetime of the UMA using this value is one
37// year (exp. Nov. 2021), five buckets are more than enough for
38// its histogram (between 0 to 4 external monitors).
39constexpr int kMaxDisplaysCount = 5;
40
Gil Dekelc8b8c4ed2022-05-04 20:30:3841// Consolidates the UMA name prefix creation to one location, since it is used
42// in many different call-sites.
43const std::string GetUmaNamePrefixForRequest(
44 const DisplayConfigureRequest& request) {
45 return request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL
46 ? std::string("ConfigureDisplays.Internal.Modeset.")
47 : std::string("ConfigureDisplays.External.Modeset.");
48}
49
Gil Dekel66a97bc2022-04-29 04:21:5050// Find the next best mode that is smaller than |request->mode|. The next best
51// mode is found by comparing resolutions, and if those are similar, comparing
52// refresh rates. If no mode is found, return nullptr.
53const DisplayMode* FindNextMode(const DisplayConfigureRequest& request) {
54 DCHECK(request.mode);
Gil Dekelbbc40352021-01-05 18:33:5655
Gil Dekel66a97bc2022-04-29 04:21:5056 // Internal displays are restricted to their native mode. We do not
57 // attempt to downgrade their modes upon failure.
58 if (request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
dnicoaraa89c2082015-01-05 16:49:0659 return nullptr;
60
Gil Dekel66a97bc2022-04-29 04:21:5061 if (request.display->modes().size() <= 1)
62 return nullptr;
63
dnicoara9372a7912014-12-11 01:29:0664 const DisplayMode* best_mode = nullptr;
Gil Dekel66a97bc2022-04-29 04:21:5065 for (const auto& mode : request.display->modes()) {
66 if (*mode < *request.mode && (!best_mode || *mode > *best_mode))
dbasehore01e90042016-05-27 06:16:5167 best_mode = mode.get();
dnicoara9372a7912014-12-11 01:29:0668 }
69
70 return best_mode;
71}
72
Gil Dekelbbc40352021-01-05 18:33:5673void LogIfInvalidRequestForInternalDisplay(
74 const DisplayConfigureRequest& request) {
75 if (request.display->type() != DISPLAY_CONNECTION_TYPE_INTERNAL)
76 return;
77
78 if (request.mode == nullptr)
79 return;
80
81 if (request.mode == request.display->native_mode())
82 return;
83
84 LOG(ERROR) << "A mode other than the preferred mode was requested for the "
85 "internal display: preferred="
86 << request.display->native_mode()->ToString()
87 << " vs. requested=" << request.mode->ToString()
88 << ". Current mode="
89 << (request.display->current_mode()
90 ? request.display->current_mode()->ToString()
91 : "nullptr (disabled)")
92 << ".";
93}
94
Daniele Castagna4f0689b2019-10-30 01:16:4795// Samples used to define buckets used by DisplayResolution enum.
96// The enum is used to record screen resolution statistics.
97const int32_t kDisplayResolutionSamples[] = {1024, 1280, 1440, 1920,
98 2560, 3840, 5120, 7680};
99
Gil Dekelc8b8c4ed2022-05-04 20:30:38100void UpdateResolutionUma(const DisplayConfigureRequest& request,
101 const std::string& uma_name) {
102 // Display is powered off.
103 if (!request.mode)
104 return;
Daniele Castagna4f0689b2019-10-30 01:16:47105
Gil Dekelc8b8c4ed2022-05-04 20:30:38106 // First, compute the index of the enum DisplayResolution.
107 // The index has to match the definition of the enum in enums.xml.
108 const uint32_t samples_list_size = std::size(kDisplayResolutionSamples);
109 const gfx::Size size = request.mode->size();
Daniele Castagna4f0689b2019-10-30 01:16:47110 uint32_t width_idx = 0;
111 uint32_t height_idx = 0;
Gil Dekelc8b8c4ed2022-05-04 20:30:38112 for (; width_idx < samples_list_size; width_idx++) {
Daniele Castagna4f0689b2019-10-30 01:16:47113 if (size.width() <= kDisplayResolutionSamples[width_idx])
114 break;
115 }
Gil Dekelc8b8c4ed2022-05-04 20:30:38116 for (; height_idx < samples_list_size; height_idx++) {
Daniele Castagna4f0689b2019-10-30 01:16:47117 if (size.height() <= kDisplayResolutionSamples[height_idx])
118 break;
119 }
120
Gil Dekelc8b8c4ed2022-05-04 20:30:38121 int display_resolution_index = 0;
122 if (width_idx == samples_list_size || height_idx == samples_list_size) {
123 // Check if we are in the overflow bucket.
124 display_resolution_index = samples_list_size * samples_list_size + 1;
125 } else {
126 // Compute the index of DisplayResolution, starting from 1, since 0 is used
127 // when powering off the display.
128 display_resolution_index = width_idx * samples_list_size + height_idx + 1;
129 }
130
131 base::UmaHistogramExactLinear(uma_name, display_resolution_index,
132 samples_list_size * samples_list_size + 2);
Daniele Castagna4f0689b2019-10-30 01:16:47133}
134
Gil Dekelc8b8c4ed2022-05-04 20:30:38135// A list of common refresh rates that are used to help fit approximate refresh
136// rate values into one of the common refresh rate bins.
137constexpr float kCommonDisplayRefreshRates[] = {
138 24.0, 25.0, 30.0, 45.0, 48.0, 50.0, 60.0, 75.0,
139 90.0, 100.0, 120.0, 144.0, 165.0, 200.0, 240.0};
Gil Dekel20dc5302020-12-01 20:03:41140
Gil Dekelc8b8c4ed2022-05-04 20:30:38141void UpdateRefreshRateUma(const DisplayConfigureRequest& request,
142 const std::string& uma_name) {
143 // Display is powered off.
144 if (!request.mode)
145 return;
Gil Dekel20dc5302020-12-01 20:03:41146
Gil Dekelc8b8c4ed2022-05-04 20:30:38147 base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
148 uma_name, base::HistogramBase::kUmaTargetedHistogramFlag);
149
150 // Check if the refresh value is within an epsilon from one of the common
151 // refresh rate values.
Gil Dekela7ca9fc2022-05-16 19:25:37152 for (float common_rate : kCommonDisplayRefreshRates) {
153 const bool is_within_epsilon = std::abs(request.mode->refresh_rate() -
154 common_rate) < kRefreshRateEpsilon;
Gil Dekelc8b8c4ed2022-05-04 20:30:38155 if (is_within_epsilon) {
Gil Dekela7ca9fc2022-05-16 19:25:37156 histogram->Add(common_rate);
Gil Dekelc8b8c4ed2022-05-04 20:30:38157 return;
158 }
159 }
160
161 // Since this is not a common refresh rate value, report it as is.
162 histogram->Add(request.mode->refresh_rate());
Gil Dekel20dc5302020-12-01 20:03:41163}
164
Gil Dekel36b941dd2021-01-23 00:37:23165void UpdateAttemptSucceededUma(
166 const std::vector<DisplayConfigureRequest>& requests,
167 bool display_success) {
168 for (const auto& request : requests) {
Gil Dekelc8b8c4ed2022-05-04 20:30:38169 const std::string uma_name_prefix = GetUmaNamePrefixForRequest(request);
170 base::UmaHistogramBoolean(uma_name_prefix + "AttemptSucceeded",
171 display_success);
Gil Dekel36b941dd2021-01-23 00:37:23172
173 VLOG(2) << "Configured status=" << display_success
174 << " display=" << request.display->display_id()
175 << " origin=" << request.origin.ToString()
Andrew Wolfers4eb4c302023-02-14 21:37:33176 << " mode=" << (request.mode ? request.mode->ToString() : "null")
177 << " enable_vrr=" << request.enable_vrr;
Gil Dekel36b941dd2021-01-23 00:37:23178 }
Gil Dekel20dc5302020-12-01 20:03:41179}
180
Gil Dekel36b941dd2021-01-23 00:37:23181void UpdateFinalStatusUma(
Gil Dekel81fc8d52023-07-26 19:40:47182 const std::vector<RequestAndStatusList>& requests_and_statuses,
183 ConfigureDisplaysTask::Status status) {
Gil Dekel20dc5302020-12-01 20:03:41184 int mst_external_displays = 0;
Gil Dekel36b941dd2021-01-23 00:37:23185 size_t total_external_displays = requests_and_statuses.size();
186 for (auto& request_and_status : requests_and_statuses) {
Gil Dekel472925e2022-05-16 18:55:27187 const DisplayConfigureRequest* request = request_and_status.first;
Gil Dekel36b941dd2021-01-23 00:37:23188
Gil Dekel20dc5302020-12-01 20:03:41189 // Is this display SST (single-stream vs. MST multi-stream).
Gil Dekel472925e2022-05-16 18:55:27190 const bool sst_display = request->display->base_connector_id() &&
191 request->display->path_topology().empty();
Gil Dekel20dc5302020-12-01 20:03:41192 if (!sst_display)
193 mst_external_displays++;
194
Gil Dekel472925e2022-05-16 18:55:27195 if (request->display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
Gil Dekel20dc5302020-12-01 20:03:41196 total_external_displays--;
197
Gil Dekel472925e2022-05-16 18:55:27198 const std::string uma_name_prefix = GetUmaNamePrefixForRequest(*request);
Gil Dekelc8b8c4ed2022-05-04 20:30:38199 if (request_and_status.second) {
Gil Dekel472925e2022-05-16 18:55:27200 UpdateResolutionUma(*request, uma_name_prefix + "Success.Resolution");
201 UpdateRefreshRateUma(*request, uma_name_prefix + "Success.RefreshRate");
Gil Dekelc8b8c4ed2022-05-04 20:30:38202 }
203 base::UmaHistogramBoolean(uma_name_prefix + "FinalStatus",
204 request_and_status.second);
Gil Dekel20dc5302020-12-01 20:03:41205 }
206
Gil Dekel81fc8d52023-07-26 19:40:47207 base::UmaHistogramEnumeration("ConfigureDisplays.Modeset.FinalTaskStatus",
208 status);
209
Gil Dekel20dc5302020-12-01 20:03:41210 base::UmaHistogramExactLinear(
211 "ConfigureDisplays.Modeset.TotalExternalDisplaysCount",
212 base::checked_cast<int>(total_external_displays), kMaxDisplaysCount);
213
214 base::UmaHistogramExactLinear(
215 "ConfigureDisplays.Modeset.MstExternalDisplaysCount",
216 mst_external_displays, kMaxDisplaysCount);
217
218 if (total_external_displays > 0) {
219 const int mst_displays_percentage =
220 100.0 * mst_external_displays / total_external_displays;
221 UMA_HISTOGRAM_PERCENTAGE(
222 "ConfigureDisplays.Modeset.MstExternalDisplaysPercentage",
223 mst_displays_percentage);
224 }
225}
226
dnicoara9372a7912014-12-11 01:29:06227} // namespace
228
229DisplayConfigureRequest::DisplayConfigureRequest(DisplaySnapshot* display,
230 const DisplayMode* mode,
Andrew Wolfers4eb4c302023-02-14 21:37:33231 const gfx::Point& origin,
232 bool enable_vrr)
233 : display(display), mode(mode), origin(origin), enable_vrr(enable_vrr) {}
234
235DisplayConfigureRequest::DisplayConfigureRequest(DisplaySnapshot* display,
236 const DisplayMode* mode,
dnicoara9372a7912014-12-11 01:29:06237 const gfx::Point& origin)
Andrew Wolfers4eb4c302023-02-14 21:37:33238 : DisplayConfigureRequest(display, mode, origin, /*enable_vrr=*/false) {}
dnicoara9372a7912014-12-11 01:29:06239
240ConfigureDisplaysTask::ConfigureDisplaysTask(
241 NativeDisplayDelegate* delegate,
242 const std::vector<DisplayConfigureRequest>& requests,
Drew Davenport7636a462022-07-21 20:14:30243 ResponseCallback callback,
244 ConfigurationType configuration_type)
dnicoara9372a7912014-12-11 01:29:06245 : delegate_(delegate),
246 requests_(requests),
Drew Davenport7636a462022-07-21 20:14:30247 configuration_type_(configuration_type),
Sylvain Defresne23395c7a2019-10-02 10:07:45248 callback_(std::move(callback)),
Jeremy Roman47d432e2019-08-20 14:24:00249 task_status_(SUCCESS) {
afakhry4e92e8c2017-04-20 17:04:59250 delegate_->AddObserver(this);
dnicoara9372a7912014-12-11 01:29:06251}
252
Gil Dekel472925e2022-05-16 18:55:27253ConfigureDisplaysTask::RequestToOriginalMode::RequestToOriginalMode(
254 DisplayConfigureRequest* request,
255 const DisplayMode* original_mode)
256 : request(request), original_mode(original_mode) {}
257
afakhry4e92e8c2017-04-20 17:04:59258ConfigureDisplaysTask::~ConfigureDisplaysTask() {
259 delegate_->RemoveObserver(this);
260}
dnicoara9372a7912014-12-11 01:29:06261
262void ConfigureDisplaysTask::Run() {
Gil Dekel3369eec2020-10-06 19:53:10263 DCHECK(!requests_.empty());
dnicoara9372a7912014-12-11 01:29:06264
Gil Dekelc8b8c4ed2022-05-04 20:30:38265 const bool is_first_attempt = pending_display_group_requests_.empty();
Gil Dekel3369eec2020-10-06 19:53:10266 std::vector<display::DisplayConfigurationParams> config_requests;
267 for (const auto& request : requests_) {
Gil Dekelbbc40352021-01-05 18:33:56268 LogIfInvalidRequestForInternalDisplay(request);
269
Gil Dekel3369eec2020-10-06 19:53:10270 config_requests.emplace_back(request.display->display_id(), request.origin,
Andrew Wolfers4eb4c302023-02-14 21:37:33271 request.mode, request.enable_vrr);
Daniele Castagna4f0689b2019-10-30 01:16:47272
Gil Dekelc8b8c4ed2022-05-04 20:30:38273 if (is_first_attempt) {
274 const std::string uma_name_prefix = GetUmaNamePrefixForRequest(request);
275 UpdateResolutionUma(request,
276 uma_name_prefix + "OriginalRequest.Resolution");
277 }
dnicoara9372a7912014-12-11 01:29:06278 }
279
Gil Dekel36b941dd2021-01-23 00:37:23280 const auto& on_configured =
Gil Dekelc8b8c4ed2022-05-04 20:30:38281 is_first_attempt ? &ConfigureDisplaysTask::OnFirstAttemptConfigured
282 : &ConfigureDisplaysTask::OnRetryConfigured;
Gil Dekel36b941dd2021-01-23 00:37:23283
Drew Davenport5686c952024-03-08 16:47:50284 display::ModesetFlags modeset_flags{display::ModesetFlag::kTestModeset};
Drew Davenport7636a462022-07-21 20:14:30285 if (configuration_type_ == kConfigurationTypeSeamless)
Drew Davenport5686c952024-03-08 16:47:50286 modeset_flags.Put(display::ModesetFlag::kSeamlessModeset);
Gil Dekel36b941dd2021-01-23 00:37:23287 delegate_->Configure(
288 config_requests,
Gil Dekelcd4c2c02022-07-19 18:01:37289 base::BindOnce(on_configured, weak_ptr_factory_.GetWeakPtr()),
Drew Davenport7636a462022-07-21 20:14:30290 modeset_flags);
dnicoara9372a7912014-12-11 01:29:06291}
292
afakhry4e92e8c2017-04-20 17:04:59293void ConfigureDisplaysTask::OnConfigurationChanged() {}
294
295void ConfigureDisplaysTask::OnDisplaySnapshotsInvalidated() {
afakhry4e92e8c2017-04-20 17:04:59296 // From now on, don't access |requests_[index]->display|; they're invalid.
297 task_status_ = ERROR;
298 weak_ptr_factory_.InvalidateWeakPtrs();
Gil Dekel3369eec2020-10-06 19:53:10299 std::move(callback_).Run(task_status_);
afakhry4e92e8c2017-04-20 17:04:59300}
301
Gil Dekel36b941dd2021-01-23 00:37:23302void ConfigureDisplaysTask::OnFirstAttemptConfigured(bool config_success) {
303 UpdateAttemptSucceededUma(requests_, config_success);
Daniele Castagna4f0689b2019-10-30 01:16:47304
Gil Dekel36b941dd2021-01-23 00:37:23305 if (!config_success) {
Gil Dekel472925e2022-05-16 18:55:27306 // Partition |requests_| into smaller groups via
307 // |pending_display_group_requests_|, update the task's state, and initiate
308 // the retry logic. The next time |delegate_|->Configure() terminates
309 // OnRetryConfigured() will be executed instead.
Gil Dekel36b941dd2021-01-23 00:37:23310 PartitionRequests();
311 DCHECK(!pending_display_group_requests_.empty());
Gil Dekel472925e2022-05-16 18:55:27312 // Prep the first group
313 for (const auto& pair : pending_display_group_requests_.front())
314 pair.request->mode = pair.original_mode;
Gil Dekel42f7aba2021-01-08 18:59:55315 task_status_ = PARTIAL_SUCCESS;
316 Run();
317 return;
dnicoara9372a7912014-12-11 01:29:06318 }
319
Gil Dekel36b941dd2021-01-23 00:37:23320 // This code execute only when the first modeset attempt fully succeeds.
Gil Dekel8f7fa0182022-07-22 17:45:14321 // Submit the current |requests_| for modeset.
322 std::vector<display::DisplayConfigurationParams> config_requests;
323 for (const auto& request : requests_) {
324 final_requests_status_.emplace_back(&request, true);
325
326 config_requests.emplace_back(request.display->display_id(), request.origin,
Andrew Wolfers4eb4c302023-02-14 21:37:33327 request.mode, request.enable_vrr);
Gil Dekel36b941dd2021-01-23 00:37:23328 }
Gil Dekel788edb62020-11-25 23:41:28329
Drew Davenport5686c952024-03-08 16:47:50330 display::ModesetFlags modeset_flags{display::ModesetFlag::kCommitModeset};
Gil Dekel8f7fa0182022-07-22 17:45:14331 if (configuration_type_ == kConfigurationTypeSeamless)
Drew Davenport5686c952024-03-08 16:47:50332 modeset_flags.Put(display::ModesetFlag::kSeamlessModeset);
Gil Dekel8f7fa0182022-07-22 17:45:14333 delegate_->Configure(config_requests,
334 base::BindOnce(&ConfigureDisplaysTask::OnConfigured,
335 weak_ptr_factory_.GetWeakPtr()),
336 modeset_flags);
dnicoara9372a7912014-12-11 01:29:06337}
338
Gil Dekel36b941dd2021-01-23 00:37:23339void ConfigureDisplaysTask::OnRetryConfigured(bool config_success) {
340 UpdateAttemptSucceededUma(requests_, config_success);
341
342 if (!config_success) {
343 // If one of the largest display request can be downgraded, try again.
344 // Otherwise this configuration task is a failure.
Gil Dekel472925e2022-05-16 18:55:27345 if (DowngradeDisplayRequestGroup()) {
Gil Dekel36b941dd2021-01-23 00:37:23346 Run();
347 return;
348 } else {
Gil Dekel472925e2022-05-16 18:55:27349 // Disable all displays in the current group, since we failed to find an
350 // alternative mode. Note that we skip modeset if the latest (or a
351 // single) pending group fails. There is no point in disabling displays
352 // that are already disabled from previous attempts and failed to change
353 // mode.
354 for (const auto& pair : pending_display_group_requests_.front())
355 pair.request->mode = nullptr;
Gil Dekel36b941dd2021-01-23 00:37:23356 task_status_ = ERROR;
357 }
Gil Dekel8f7fa0182022-07-22 17:45:14358 } else {
359 // This configuration attempt passed test-modeset. Cache it so we can use it
360 // to modeset the displays once we are done testing, or if no other future
361 // attempts succeed.
362 last_successful_config_parameters_.clear();
363 for (const auto& request : requests_) {
364 last_successful_config_parameters_.emplace_back(
Andrew Wolfers4eb4c302023-02-14 21:37:33365 request.display->display_id(), request.origin, request.mode,
366 request.enable_vrr);
Gil Dekel8f7fa0182022-07-22 17:45:14367 }
Gil Dekel36b941dd2021-01-23 00:37:23368 }
369
370 // This code executes only when this display group request fully succeeds or
371 // fails to modeset. Update the final status of this group.
Gil Dekel8f7fa0182022-07-22 17:45:14372 for (const auto& pair : pending_display_group_requests_.front())
373 final_requests_status_.emplace_back(pair.request, config_success);
Gil Dekel36b941dd2021-01-23 00:37:23374
375 // Subsequent modeset attempts will be done on the next pending display group,
376 // if one exists.
377 pending_display_group_requests_.pop();
Gil Dekel36b941dd2021-01-23 00:37:23378 if (!pending_display_group_requests_.empty()) {
Gil Dekel472925e2022-05-16 18:55:27379 // Prep the next group
380 for (const auto& pair : pending_display_group_requests_.front())
381 pair.request->mode = pair.original_mode;
Gil Dekel36b941dd2021-01-23 00:37:23382 Run();
383 return;
384 }
385
Gil Dekel8f7fa0182022-07-22 17:45:14386 if (task_status_ == ERROR) {
387 LOG(WARNING) << "One or more of the connected display groups failed to "
388 "pass test-modeset entirely and will be disabled.";
389
390 if (last_successful_config_parameters_.empty()) {
391 LOG(ERROR) << "Display configuration failed. No modeset was attempted.";
392
Gil Dekel81fc8d52023-07-26 19:40:47393 UpdateFinalStatusUma(final_requests_status_, task_status_);
Gil Dekel8f7fa0182022-07-22 17:45:14394 std::move(callback_).Run(task_status_);
395 return;
396 }
397 }
398
399 // Configure the displays using the last successful configuration parameter
400 // list.
Drew Davenport5686c952024-03-08 16:47:50401 display::ModesetFlags modeset_flags{display::ModesetFlag::kCommitModeset};
Gil Dekel8f7fa0182022-07-22 17:45:14402 if (configuration_type_ == kConfigurationTypeSeamless)
Drew Davenport5686c952024-03-08 16:47:50403 modeset_flags.Put(display::ModesetFlag::kSeamlessModeset);
Gil Dekel8f7fa0182022-07-22 17:45:14404 delegate_->Configure(last_successful_config_parameters_,
405 base::BindOnce(&ConfigureDisplaysTask::OnConfigured,
406 weak_ptr_factory_.GetWeakPtr()),
407 modeset_flags);
408}
409
410void ConfigureDisplaysTask::OnConfigured(bool config_success) {
411 if (config_success) {
412 for (const DisplayConfigureRequest& request : requests_) {
413 request.display->set_current_mode(request.mode);
414 request.display->set_origin(request.origin);
Andrew Wolfers4eb4c302023-02-14 21:37:33415 if (request.display->IsVrrCapable()) {
416 request.display->set_variable_refresh_rate_state(
417 request.enable_vrr ? display::kVrrEnabled : display::kVrrDisabled);
418 }
Gil Dekel8f7fa0182022-07-22 17:45:14419 }
420 }
421
Gil Dekel81fc8d52023-07-26 19:40:47422 UpdateFinalStatusUma(final_requests_status_, task_status_);
Gil Dekel36b941dd2021-01-23 00:37:23423 std::move(callback_).Run(task_status_);
424}
425
426void ConfigureDisplaysTask::PartitionRequests() {
427 pending_display_group_requests_ = PartitionedRequestsQueue();
Gil Dekel36b941dd2021-01-23 00:37:23428
Mark Yacoub100f2df2022-04-19 18:01:14429 base::flat_set<uint64_t> handled_connectors;
Gil Dekel36b941dd2021-01-23 00:37:23430 for (size_t i = 0; i < requests_.size(); ++i) {
431 uint64_t connector_id = requests_[i].display->base_connector_id();
432 if (handled_connectors.find(connector_id) != handled_connectors.end())
433 continue;
434
Gil Dekel472925e2022-05-16 18:55:27435 std::vector<ConfigureDisplaysTask::RequestToOriginalMode> request_group;
Gil Dekel36b941dd2021-01-23 00:37:23436 for (size_t j = i; j < requests_.size(); ++j) {
Gil Dekel472925e2022-05-16 18:55:27437 if (connector_id == requests_[j].display->base_connector_id()) {
438 // Disable all requests in preparation increment connector retries after
439 // mapping them to their original request.
440 request_group.emplace_back(&requests_[j], requests_[j].mode);
441 requests_[j].mode = nullptr;
442 }
Gil Dekel36b941dd2021-01-23 00:37:23443 }
444
Gil Dekel36b941dd2021-01-23 00:37:23445 handled_connectors.insert(connector_id);
Mark Yacoub100f2df2022-04-19 18:01:14446 pending_display_group_requests_.push(request_group);
Gil Dekel36b941dd2021-01-23 00:37:23447 }
448}
449
Gil Dekel472925e2022-05-16 18:55:27450bool ConfigureDisplaysTask::DowngradeDisplayRequestGroup() {
Gil Dekel36b941dd2021-01-23 00:37:23451 auto cmp = [](DisplayConfigureRequest* lhs, DisplayConfigureRequest* rhs) {
452 return *lhs->mode < *rhs->mode;
453 };
454 std::priority_queue<DisplayConfigureRequest*,
455 std::vector<DisplayConfigureRequest*>, decltype(cmp)>
456 sorted_requests(cmp);
457
Gil Dekel472925e2022-05-16 18:55:27458 for (const auto& pair : pending_display_group_requests_.front()) {
459 if (pair.request->display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
Gil Dekel36b941dd2021-01-23 00:37:23460 continue;
461
Gil Dekel472925e2022-05-16 18:55:27462 if (!pair.request->mode)
Gil Dekel36b941dd2021-01-23 00:37:23463 continue;
464
Gil Dekel472925e2022-05-16 18:55:27465 sorted_requests.push(pair.request);
Gil Dekel36b941dd2021-01-23 00:37:23466 }
467
468 // Fail if there are no viable candidates to downgrade
469 if (sorted_requests.empty())
470 return false;
471
472 while (!sorted_requests.empty()) {
473 DisplayConfigureRequest* next_request = sorted_requests.top();
474 sorted_requests.pop();
475
Gil Dekel66a97bc2022-04-29 04:21:50476 const DisplayMode* next_mode = FindNextMode(*next_request);
Gil Dekel36b941dd2021-01-23 00:37:23477 if (next_mode) {
478 next_request->mode = next_mode;
479 return true;
480 }
481 }
482
483 return false;
484}
485
kylechar7a067ec2017-01-07 01:16:28486} // namespace display