blob: 0a294bf1a15204e803d85c37952081036d554da8 [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
dnicoara9372a7912014-12-11 01:29:0610#include "base/auto_reset.h"
Gil Dekel36b941dd2021-01-23 00:37:2311#include "base/containers/flat_set.h"
Brett Wilsonb02c0a22017-09-25 22:34:4212#include "base/containers/queue.h"
Avi Drissmanc149c162023-01-12 02:16:5913#include "base/functional/bind.h"
Hans Wennborg3930cf32020-06-17 16:29:5214#include "base/logging.h"
Daniele Castagna4f0689b2019-10-30 01:16:4715#include "base/metrics/histogram_functions.h"
Gil Dekel788edb62020-11-25 23:41:2816#include "base/metrics/histogram_macros.h"
Gil Dekelc8b8c4ed2022-05-04 20:30:3817#include "base/metrics/sparse_histogram.h"
Gil Dekel788edb62020-11-25 23:41:2818#include "base/numerics/safe_conversions.h"
Mitsuru Oshima96ff4542022-05-02 17:31:3219#include "ui/display/manager/display_manager_util.h"
Mark Yacoubd18a2922020-07-07 01:14:1520#include "ui/display/types/display_configuration_params.h"
Gil Dekelbbc40352021-01-05 18:33:5621#include "ui/display/types/display_constants.h"
Gil Dekel36b941dd2021-01-23 00:37:2322#include "ui/display/types/display_mode.h"
dnicoara9372a7912014-12-11 01:29:0623#include "ui/display/types/display_snapshot.h"
24#include "ui/display/types/native_display_delegate.h"
25
kylechar7a067ec2017-01-07 01:16:2826namespace display {
dnicoara9372a7912014-12-11 01:29:0627
28namespace {
29
Gil Dekelc8b8c4ed2022-05-04 20:30:3830// The epsilon by which a refresh rate value may drift. For example:
31// 239.76Hz --> 240Hz. This value was chosen with the consideration of the
32// refresh rate value drifts presented in the "Video Formats—Video ID Code and
33// Aspect Ratios" table on p.40 of the CTA-861-G standard.
34constexpr float kRefreshRateEpsilon = 0.5f;
35
Gil Dekel788edb62020-11-25 23:41:2836// Because we do not offer hardware mirroring, the maximal number of external
37// displays that can be configured is limited by the number of available CRTCs,
38// which is usually three. Since the lifetime of the UMA using this value is one
39// year (exp. Nov. 2021), five buckets are more than enough for
40// its histogram (between 0 to 4 external monitors).
41constexpr int kMaxDisplaysCount = 5;
42
Gil Dekelc8b8c4ed2022-05-04 20:30:3843// Consolidates the UMA name prefix creation to one location, since it is used
44// in many different call-sites.
45const std::string GetUmaNamePrefixForRequest(
46 const DisplayConfigureRequest& request) {
47 return request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL
48 ? std::string("ConfigureDisplays.Internal.Modeset.")
49 : std::string("ConfigureDisplays.External.Modeset.");
50}
51
Gil Dekel66a97bc2022-04-29 04:21:5052// Find the next best mode that is smaller than |request->mode|. The next best
53// mode is found by comparing resolutions, and if those are similar, comparing
54// refresh rates. If no mode is found, return nullptr.
55const DisplayMode* FindNextMode(const DisplayConfigureRequest& request) {
56 DCHECK(request.mode);
Gil Dekelbbc40352021-01-05 18:33:5657
Gil Dekel66a97bc2022-04-29 04:21:5058 // Internal displays are restricted to their native mode. We do not
59 // attempt to downgrade their modes upon failure.
60 if (request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
dnicoaraa89c2082015-01-05 16:49:0661 return nullptr;
62
Gil Dekel66a97bc2022-04-29 04:21:5063 if (request.display->modes().size() <= 1)
64 return nullptr;
65
dnicoara9372a7912014-12-11 01:29:0666 const DisplayMode* best_mode = nullptr;
Gil Dekel66a97bc2022-04-29 04:21:5067 for (const auto& mode : request.display->modes()) {
68 if (*mode < *request.mode && (!best_mode || *mode > *best_mode))
dbasehore01e90042016-05-27 06:16:5169 best_mode = mode.get();
dnicoara9372a7912014-12-11 01:29:0670 }
71
72 return best_mode;
73}
74
Gil Dekelbbc40352021-01-05 18:33:5675void LogIfInvalidRequestForInternalDisplay(
76 const DisplayConfigureRequest& request) {
77 if (request.display->type() != DISPLAY_CONNECTION_TYPE_INTERNAL)
78 return;
79
80 if (request.mode == nullptr)
81 return;
82
83 if (request.mode == request.display->native_mode())
84 return;
85
86 LOG(ERROR) << "A mode other than the preferred mode was requested for the "
87 "internal display: preferred="
88 << request.display->native_mode()->ToString()
89 << " vs. requested=" << request.mode->ToString()
90 << ". Current mode="
91 << (request.display->current_mode()
92 ? request.display->current_mode()->ToString()
93 : "nullptr (disabled)")
94 << ".";
95}
96
Daniele Castagna4f0689b2019-10-30 01:16:4797// Samples used to define buckets used by DisplayResolution enum.
98// The enum is used to record screen resolution statistics.
99const int32_t kDisplayResolutionSamples[] = {1024, 1280, 1440, 1920,
100 2560, 3840, 5120, 7680};
101
Gil Dekelc8b8c4ed2022-05-04 20:30:38102void UpdateResolutionUma(const DisplayConfigureRequest& request,
103 const std::string& uma_name) {
104 // Display is powered off.
105 if (!request.mode)
106 return;
Daniele Castagna4f0689b2019-10-30 01:16:47107
Gil Dekelc8b8c4ed2022-05-04 20:30:38108 // First, compute the index of the enum DisplayResolution.
109 // The index has to match the definition of the enum in enums.xml.
110 const uint32_t samples_list_size = std::size(kDisplayResolutionSamples);
111 const gfx::Size size = request.mode->size();
Daniele Castagna4f0689b2019-10-30 01:16:47112 uint32_t width_idx = 0;
113 uint32_t height_idx = 0;
Gil Dekelc8b8c4ed2022-05-04 20:30:38114 for (; width_idx < samples_list_size; width_idx++) {
Daniele Castagna4f0689b2019-10-30 01:16:47115 if (size.width() <= kDisplayResolutionSamples[width_idx])
116 break;
117 }
Gil Dekelc8b8c4ed2022-05-04 20:30:38118 for (; height_idx < samples_list_size; height_idx++) {
Daniele Castagna4f0689b2019-10-30 01:16:47119 if (size.height() <= kDisplayResolutionSamples[height_idx])
120 break;
121 }
122
Gil Dekelc8b8c4ed2022-05-04 20:30:38123 int display_resolution_index = 0;
124 if (width_idx == samples_list_size || height_idx == samples_list_size) {
125 // Check if we are in the overflow bucket.
126 display_resolution_index = samples_list_size * samples_list_size + 1;
127 } else {
128 // Compute the index of DisplayResolution, starting from 1, since 0 is used
129 // when powering off the display.
130 display_resolution_index = width_idx * samples_list_size + height_idx + 1;
131 }
132
133 base::UmaHistogramExactLinear(uma_name, display_resolution_index,
134 samples_list_size * samples_list_size + 2);
Daniele Castagna4f0689b2019-10-30 01:16:47135}
136
Gil Dekelc8b8c4ed2022-05-04 20:30:38137// A list of common refresh rates that are used to help fit approximate refresh
138// rate values into one of the common refresh rate bins.
139constexpr float kCommonDisplayRefreshRates[] = {
140 24.0, 25.0, 30.0, 45.0, 48.0, 50.0, 60.0, 75.0,
141 90.0, 100.0, 120.0, 144.0, 165.0, 200.0, 240.0};
Gil Dekel20dc5302020-12-01 20:03:41142
Gil Dekelc8b8c4ed2022-05-04 20:30:38143void UpdateRefreshRateUma(const DisplayConfigureRequest& request,
144 const std::string& uma_name) {
145 // Display is powered off.
146 if (!request.mode)
147 return;
Gil Dekel20dc5302020-12-01 20:03:41148
Gil Dekelc8b8c4ed2022-05-04 20:30:38149 base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
150 uma_name, base::HistogramBase::kUmaTargetedHistogramFlag);
151
152 // Check if the refresh value is within an epsilon from one of the common
153 // refresh rate values.
Gil Dekela7ca9fc2022-05-16 19:25:37154 for (float common_rate : kCommonDisplayRefreshRates) {
155 const bool is_within_epsilon = std::abs(request.mode->refresh_rate() -
156 common_rate) < kRefreshRateEpsilon;
Gil Dekelc8b8c4ed2022-05-04 20:30:38157 if (is_within_epsilon) {
Gil Dekela7ca9fc2022-05-16 19:25:37158 histogram->Add(common_rate);
Gil Dekelc8b8c4ed2022-05-04 20:30:38159 return;
160 }
161 }
162
163 // Since this is not a common refresh rate value, report it as is.
164 histogram->Add(request.mode->refresh_rate());
Gil Dekel20dc5302020-12-01 20:03:41165}
166
Gil Dekel36b941dd2021-01-23 00:37:23167void UpdateAttemptSucceededUma(
168 const std::vector<DisplayConfigureRequest>& requests,
169 bool display_success) {
170 for (const auto& request : requests) {
Gil Dekelc8b8c4ed2022-05-04 20:30:38171 const std::string uma_name_prefix = GetUmaNamePrefixForRequest(request);
172 base::UmaHistogramBoolean(uma_name_prefix + "AttemptSucceeded",
173 display_success);
Gil Dekel36b941dd2021-01-23 00:37:23174
175 VLOG(2) << "Configured status=" << display_success
176 << " display=" << request.display->display_id()
177 << " origin=" << request.origin.ToString()
178 << " mode=" << (request.mode ? request.mode->ToString() : "null");
179 }
Gil Dekel20dc5302020-12-01 20:03:41180}
181
Gil Dekel36b941dd2021-01-23 00:37:23182void UpdateFinalStatusUma(
183 const std::vector<RequestAndStatusList>& requests_and_statuses) {
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
207 base::UmaHistogramExactLinear(
208 "ConfigureDisplays.Modeset.TotalExternalDisplaysCount",
209 base::checked_cast<int>(total_external_displays), kMaxDisplaysCount);
210
211 base::UmaHistogramExactLinear(
212 "ConfigureDisplays.Modeset.MstExternalDisplaysCount",
213 mst_external_displays, kMaxDisplaysCount);
214
215 if (total_external_displays > 0) {
216 const int mst_displays_percentage =
217 100.0 * mst_external_displays / total_external_displays;
218 UMA_HISTOGRAM_PERCENTAGE(
219 "ConfigureDisplays.Modeset.MstExternalDisplaysPercentage",
220 mst_displays_percentage);
221 }
222}
223
dnicoara9372a7912014-12-11 01:29:06224} // namespace
225
226DisplayConfigureRequest::DisplayConfigureRequest(DisplaySnapshot* display,
227 const DisplayMode* mode,
228 const gfx::Point& origin)
kylechar731f85f92016-12-01 20:50:46229 : display(display), mode(mode), origin(origin) {}
dnicoara9372a7912014-12-11 01:29:06230
231ConfigureDisplaysTask::ConfigureDisplaysTask(
232 NativeDisplayDelegate* delegate,
233 const std::vector<DisplayConfigureRequest>& requests,
Drew Davenport7636a462022-07-21 20:14:30234 ResponseCallback callback,
235 ConfigurationType configuration_type)
dnicoara9372a7912014-12-11 01:29:06236 : delegate_(delegate),
237 requests_(requests),
Drew Davenport7636a462022-07-21 20:14:30238 configuration_type_(configuration_type),
Sylvain Defresne23395c7a2019-10-02 10:07:45239 callback_(std::move(callback)),
Jeremy Roman47d432e2019-08-20 14:24:00240 task_status_(SUCCESS) {
afakhry4e92e8c2017-04-20 17:04:59241 delegate_->AddObserver(this);
dnicoara9372a7912014-12-11 01:29:06242}
243
Gil Dekel472925e2022-05-16 18:55:27244ConfigureDisplaysTask::RequestToOriginalMode::RequestToOriginalMode(
245 DisplayConfigureRequest* request,
246 const DisplayMode* original_mode)
247 : request(request), original_mode(original_mode) {}
248
afakhry4e92e8c2017-04-20 17:04:59249ConfigureDisplaysTask::~ConfigureDisplaysTask() {
250 delegate_->RemoveObserver(this);
251}
dnicoara9372a7912014-12-11 01:29:06252
253void ConfigureDisplaysTask::Run() {
Gil Dekel3369eec2020-10-06 19:53:10254 DCHECK(!requests_.empty());
dnicoara9372a7912014-12-11 01:29:06255
Gil Dekelc8b8c4ed2022-05-04 20:30:38256 const bool is_first_attempt = pending_display_group_requests_.empty();
Gil Dekel3369eec2020-10-06 19:53:10257 std::vector<display::DisplayConfigurationParams> config_requests;
258 for (const auto& request : requests_) {
Gil Dekelbbc40352021-01-05 18:33:56259 LogIfInvalidRequestForInternalDisplay(request);
260
Gil Dekel3369eec2020-10-06 19:53:10261 config_requests.emplace_back(request.display->display_id(), request.origin,
262 request.mode);
Daniele Castagna4f0689b2019-10-30 01:16:47263
Gil Dekelc8b8c4ed2022-05-04 20:30:38264 if (is_first_attempt) {
265 const std::string uma_name_prefix = GetUmaNamePrefixForRequest(request);
266 UpdateResolutionUma(request,
267 uma_name_prefix + "OriginalRequest.Resolution");
268 }
dnicoara9372a7912014-12-11 01:29:06269 }
270
Gil Dekel36b941dd2021-01-23 00:37:23271 const auto& on_configured =
Gil Dekelc8b8c4ed2022-05-04 20:30:38272 is_first_attempt ? &ConfigureDisplaysTask::OnFirstAttemptConfigured
273 : &ConfigureDisplaysTask::OnRetryConfigured;
Gil Dekel36b941dd2021-01-23 00:37:23274
Gil Dekel8f7fa0182022-07-22 17:45:14275 uint32_t modeset_flags = display::kTestModeset;
Drew Davenport7636a462022-07-21 20:14:30276 if (configuration_type_ == kConfigurationTypeSeamless)
277 modeset_flags |= display::kSeamlessModeset;
Gil Dekel36b941dd2021-01-23 00:37:23278 delegate_->Configure(
279 config_requests,
Gil Dekelcd4c2c02022-07-19 18:01:37280 base::BindOnce(on_configured, weak_ptr_factory_.GetWeakPtr()),
Drew Davenport7636a462022-07-21 20:14:30281 modeset_flags);
dnicoara9372a7912014-12-11 01:29:06282}
283
afakhry4e92e8c2017-04-20 17:04:59284void ConfigureDisplaysTask::OnConfigurationChanged() {}
285
286void ConfigureDisplaysTask::OnDisplaySnapshotsInvalidated() {
afakhry4e92e8c2017-04-20 17:04:59287 // From now on, don't access |requests_[index]->display|; they're invalid.
288 task_status_ = ERROR;
289 weak_ptr_factory_.InvalidateWeakPtrs();
Gil Dekel3369eec2020-10-06 19:53:10290 std::move(callback_).Run(task_status_);
afakhry4e92e8c2017-04-20 17:04:59291}
292
Gil Dekel36b941dd2021-01-23 00:37:23293void ConfigureDisplaysTask::OnFirstAttemptConfigured(bool config_success) {
294 UpdateAttemptSucceededUma(requests_, config_success);
Daniele Castagna4f0689b2019-10-30 01:16:47295
Gil Dekel36b941dd2021-01-23 00:37:23296 if (!config_success) {
Gil Dekel472925e2022-05-16 18:55:27297 // Partition |requests_| into smaller groups via
298 // |pending_display_group_requests_|, update the task's state, and initiate
299 // the retry logic. The next time |delegate_|->Configure() terminates
300 // OnRetryConfigured() will be executed instead.
Gil Dekel36b941dd2021-01-23 00:37:23301 PartitionRequests();
302 DCHECK(!pending_display_group_requests_.empty());
Gil Dekel472925e2022-05-16 18:55:27303 // Prep the first group
304 for (const auto& pair : pending_display_group_requests_.front())
305 pair.request->mode = pair.original_mode;
Gil Dekel42f7aba2021-01-08 18:59:55306 task_status_ = PARTIAL_SUCCESS;
307 Run();
308 return;
dnicoara9372a7912014-12-11 01:29:06309 }
310
Gil Dekel36b941dd2021-01-23 00:37:23311 // This code execute only when the first modeset attempt fully succeeds.
Gil Dekel8f7fa0182022-07-22 17:45:14312 // Submit the current |requests_| for modeset.
313 std::vector<display::DisplayConfigurationParams> config_requests;
314 for (const auto& request : requests_) {
315 final_requests_status_.emplace_back(&request, true);
316
317 config_requests.emplace_back(request.display->display_id(), request.origin,
318 request.mode);
Gil Dekel36b941dd2021-01-23 00:37:23319 }
Gil Dekel788edb62020-11-25 23:41:28320
Gil Dekel8f7fa0182022-07-22 17:45:14321 uint32_t modeset_flags = display::kCommitModeset;
322 if (configuration_type_ == kConfigurationTypeSeamless)
323 modeset_flags |= display::kSeamlessModeset;
324 delegate_->Configure(config_requests,
325 base::BindOnce(&ConfigureDisplaysTask::OnConfigured,
326 weak_ptr_factory_.GetWeakPtr()),
327 modeset_flags);
dnicoara9372a7912014-12-11 01:29:06328}
329
Gil Dekel36b941dd2021-01-23 00:37:23330void ConfigureDisplaysTask::OnRetryConfigured(bool config_success) {
331 UpdateAttemptSucceededUma(requests_, config_success);
332
333 if (!config_success) {
334 // If one of the largest display request can be downgraded, try again.
335 // Otherwise this configuration task is a failure.
Gil Dekel472925e2022-05-16 18:55:27336 if (DowngradeDisplayRequestGroup()) {
Gil Dekel36b941dd2021-01-23 00:37:23337 Run();
338 return;
339 } else {
Gil Dekel472925e2022-05-16 18:55:27340 // Disable all displays in the current group, since we failed to find an
341 // alternative mode. Note that we skip modeset if the latest (or a
342 // single) pending group fails. There is no point in disabling displays
343 // that are already disabled from previous attempts and failed to change
344 // mode.
345 for (const auto& pair : pending_display_group_requests_.front())
346 pair.request->mode = nullptr;
Gil Dekel36b941dd2021-01-23 00:37:23347 task_status_ = ERROR;
348 }
Gil Dekel8f7fa0182022-07-22 17:45:14349 } else {
350 // This configuration attempt passed test-modeset. Cache it so we can use it
351 // to modeset the displays once we are done testing, or if no other future
352 // attempts succeed.
353 last_successful_config_parameters_.clear();
354 for (const auto& request : requests_) {
355 last_successful_config_parameters_.emplace_back(
356 request.display->display_id(), request.origin, request.mode);
357 }
Gil Dekel36b941dd2021-01-23 00:37:23358 }
359
360 // This code executes only when this display group request fully succeeds or
361 // fails to modeset. Update the final status of this group.
Gil Dekel8f7fa0182022-07-22 17:45:14362 for (const auto& pair : pending_display_group_requests_.front())
363 final_requests_status_.emplace_back(pair.request, config_success);
Gil Dekel36b941dd2021-01-23 00:37:23364
365 // Subsequent modeset attempts will be done on the next pending display group,
366 // if one exists.
367 pending_display_group_requests_.pop();
Gil Dekel36b941dd2021-01-23 00:37:23368 if (!pending_display_group_requests_.empty()) {
Gil Dekel472925e2022-05-16 18:55:27369 // Prep the next group
370 for (const auto& pair : pending_display_group_requests_.front())
371 pair.request->mode = pair.original_mode;
Gil Dekel36b941dd2021-01-23 00:37:23372 Run();
373 return;
374 }
375
Gil Dekel8f7fa0182022-07-22 17:45:14376 if (task_status_ == ERROR) {
377 LOG(WARNING) << "One or more of the connected display groups failed to "
378 "pass test-modeset entirely and will be disabled.";
379
380 if (last_successful_config_parameters_.empty()) {
381 LOG(ERROR) << "Display configuration failed. No modeset was attempted.";
382
383 UpdateFinalStatusUma(final_requests_status_);
384 std::move(callback_).Run(task_status_);
385 return;
386 }
387 }
388
389 // Configure the displays using the last successful configuration parameter
390 // list.
391 uint32_t modeset_flags = display::kCommitModeset;
392 if (configuration_type_ == kConfigurationTypeSeamless)
393 modeset_flags |= display::kSeamlessModeset;
394 delegate_->Configure(last_successful_config_parameters_,
395 base::BindOnce(&ConfigureDisplaysTask::OnConfigured,
396 weak_ptr_factory_.GetWeakPtr()),
397 modeset_flags);
398}
399
400void ConfigureDisplaysTask::OnConfigured(bool config_success) {
401 if (config_success) {
402 for (const DisplayConfigureRequest& request : requests_) {
403 request.display->set_current_mode(request.mode);
404 request.display->set_origin(request.origin);
405 }
406 }
407
Gil Dekel36b941dd2021-01-23 00:37:23408 UpdateFinalStatusUma(final_requests_status_);
409 std::move(callback_).Run(task_status_);
410}
411
412void ConfigureDisplaysTask::PartitionRequests() {
413 pending_display_group_requests_ = PartitionedRequestsQueue();
Gil Dekel36b941dd2021-01-23 00:37:23414
Mark Yacoub100f2df2022-04-19 18:01:14415 base::flat_set<uint64_t> handled_connectors;
Gil Dekel36b941dd2021-01-23 00:37:23416 for (size_t i = 0; i < requests_.size(); ++i) {
417 uint64_t connector_id = requests_[i].display->base_connector_id();
418 if (handled_connectors.find(connector_id) != handled_connectors.end())
419 continue;
420
Gil Dekel472925e2022-05-16 18:55:27421 std::vector<ConfigureDisplaysTask::RequestToOriginalMode> request_group;
Gil Dekel36b941dd2021-01-23 00:37:23422 for (size_t j = i; j < requests_.size(); ++j) {
Gil Dekel472925e2022-05-16 18:55:27423 if (connector_id == requests_[j].display->base_connector_id()) {
424 // Disable all requests in preparation increment connector retries after
425 // mapping them to their original request.
426 request_group.emplace_back(&requests_[j], requests_[j].mode);
427 requests_[j].mode = nullptr;
428 }
Gil Dekel36b941dd2021-01-23 00:37:23429 }
430
Gil Dekel36b941dd2021-01-23 00:37:23431 handled_connectors.insert(connector_id);
Mark Yacoub100f2df2022-04-19 18:01:14432 pending_display_group_requests_.push(request_group);
Gil Dekel36b941dd2021-01-23 00:37:23433 }
434}
435
Gil Dekel472925e2022-05-16 18:55:27436bool ConfigureDisplaysTask::DowngradeDisplayRequestGroup() {
Gil Dekel36b941dd2021-01-23 00:37:23437 auto cmp = [](DisplayConfigureRequest* lhs, DisplayConfigureRequest* rhs) {
438 return *lhs->mode < *rhs->mode;
439 };
440 std::priority_queue<DisplayConfigureRequest*,
441 std::vector<DisplayConfigureRequest*>, decltype(cmp)>
442 sorted_requests(cmp);
443
Gil Dekel472925e2022-05-16 18:55:27444 for (const auto& pair : pending_display_group_requests_.front()) {
445 if (pair.request->display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
Gil Dekel36b941dd2021-01-23 00:37:23446 continue;
447
Gil Dekel472925e2022-05-16 18:55:27448 if (!pair.request->mode)
Gil Dekel36b941dd2021-01-23 00:37:23449 continue;
450
Gil Dekel472925e2022-05-16 18:55:27451 sorted_requests.push(pair.request);
Gil Dekel36b941dd2021-01-23 00:37:23452 }
453
454 // Fail if there are no viable candidates to downgrade
455 if (sorted_requests.empty())
456 return false;
457
458 while (!sorted_requests.empty()) {
459 DisplayConfigureRequest* next_request = sorted_requests.top();
460 sorted_requests.pop();
461
Gil Dekel66a97bc2022-04-29 04:21:50462 const DisplayMode* next_mode = FindNextMode(*next_request);
Gil Dekel36b941dd2021-01-23 00:37:23463 if (next_mode) {
464 next_request->mode = next_mode;
465 return true;
466 }
467 }
468
469 return false;
470}
471
kylechar7a067ec2017-01-07 01:16:28472} // namespace display