blob: f3a16a266a4b3d12e0437e909eaa109345198ffb [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
Arthur Sonzognide351fd2024-08-02 18:11:285#ifdef UNSAFE_BUFFERS_BUILD
6// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
7#pragma allow_unsafe_buffers
8#endif
9
Joone Hurd3ae8732018-04-17 18:05:0910#include "ui/display/manager/configure_displays_task.h"
dnicoara9372a7912014-12-11 01:29:0611
Gil Dekel788edb62020-11-25 23:41:2812#include <cstddef>
Gil Dekelc8b8c4ed2022-05-04 20:30:3813#include <string>
Gil Dekel788edb62020-11-25 23:41:2814
Gil Dekel36b941dd2021-01-23 00:37:2315#include "base/containers/flat_set.h"
Avi Drissmanc149c162023-01-12 02:16:5916#include "base/functional/bind.h"
Hans Wennborg3930cf32020-06-17 16:29:5217#include "base/logging.h"
Daniele Castagna4f0689b2019-10-30 01:16:4718#include "base/metrics/histogram_functions.h"
Gil Dekel788edb62020-11-25 23:41:2819#include "base/metrics/histogram_macros.h"
Gil Dekelc8b8c4ed2022-05-04 20:30:3820#include "base/metrics/sparse_histogram.h"
Gil Dekel788edb62020-11-25 23:41:2821#include "base/numerics/safe_conversions.h"
Drew Davenport3e89c1b02024-05-09 22:12:0822#include "base/strings/string_number_conversions.h"
Gil Dekela6690b72023-05-02 18:59:0423#include "ui/display/manager/util/display_manager_util.h"
Mark Yacoubd18a2922020-07-07 01:14:1524#include "ui/display/types/display_configuration_params.h"
Gil Dekelbbc40352021-01-05 18:33:5625#include "ui/display/types/display_constants.h"
Gil Dekel36b941dd2021-01-23 00:37:2326#include "ui/display/types/display_mode.h"
dnicoara9372a7912014-12-11 01:29:0627#include "ui/display/types/display_snapshot.h"
28#include "ui/display/types/native_display_delegate.h"
29
kylechar7a067ec2017-01-07 01:16:2830namespace display {
dnicoara9372a7912014-12-11 01:29:0631
32namespace {
33
Gil Dekelc8b8c4ed2022-05-04 20:30:3834// The epsilon by which a refresh rate value may drift. For example:
35// 239.76Hz --> 240Hz. This value was chosen with the consideration of the
36// refresh rate value drifts presented in the "Video Formats—Video ID Code and
37// Aspect Ratios" table on p.40 of the CTA-861-G standard.
38constexpr float kRefreshRateEpsilon = 0.5f;
39
Gil Dekel788edb62020-11-25 23:41:2840// Because we do not offer hardware mirroring, the maximal number of external
41// displays that can be configured is limited by the number of available CRTCs,
42// which is usually three. Since the lifetime of the UMA using this value is one
43// year (exp. Nov. 2021), five buckets are more than enough for
44// its histogram (between 0 to 4 external monitors).
45constexpr int kMaxDisplaysCount = 5;
46
Gil Dekelc8b8c4ed2022-05-04 20:30:3847// Consolidates the UMA name prefix creation to one location, since it is used
48// in many different call-sites.
49const std::string GetUmaNamePrefixForRequest(
50 const DisplayConfigureRequest& request) {
51 return request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL
52 ? std::string("ConfigureDisplays.Internal.Modeset.")
53 : std::string("ConfigureDisplays.External.Modeset.");
54}
55
Gil Dekel66a97bc2022-04-29 04:21:5056// Find the next best mode that is smaller than |request->mode|. The next best
57// mode is found by comparing resolutions, and if those are similar, comparing
58// refresh rates. If no mode is found, return nullptr.
59const DisplayMode* FindNextMode(const DisplayConfigureRequest& request) {
60 DCHECK(request.mode);
Gil Dekelbbc40352021-01-05 18:33:5661
Gil Dekel66a97bc2022-04-29 04:21:5062 // Internal displays are restricted to their native mode. We do not
63 // attempt to downgrade their modes upon failure.
64 if (request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
dnicoaraa89c2082015-01-05 16:49:0665 return nullptr;
66
Gil Dekel66a97bc2022-04-29 04:21:5067 if (request.display->modes().size() <= 1)
68 return nullptr;
69
dnicoara9372a7912014-12-11 01:29:0670 const DisplayMode* best_mode = nullptr;
Gil Dekel66a97bc2022-04-29 04:21:5071 for (const auto& mode : request.display->modes()) {
72 if (*mode < *request.mode && (!best_mode || *mode > *best_mode))
dbasehore01e90042016-05-27 06:16:5173 best_mode = mode.get();
dnicoara9372a7912014-12-11 01:29:0674 }
75
76 return best_mode;
77}
78
Gil Dekelbbc40352021-01-05 18:33:5679void LogIfInvalidRequestForInternalDisplay(
80 const DisplayConfigureRequest& request) {
81 if (request.display->type() != DISPLAY_CONNECTION_TYPE_INTERNAL)
82 return;
83
84 if (request.mode == nullptr)
85 return;
86
Andrew Wolfers54db3092024-07-17 18:57:1587 if (request.display->native_mode() &&
88 *request.mode == *request.display->native_mode()) {
Gil Dekelbbc40352021-01-05 18:33:5689 return;
Andrew Wolfers54db3092024-07-17 18:57:1590 }
Gil Dekelbbc40352021-01-05 18:33:5691
92 LOG(ERROR) << "A mode other than the preferred mode was requested for the "
93 "internal display: preferred="
94 << request.display->native_mode()->ToString()
95 << " vs. requested=" << request.mode->ToString()
96 << ". Current mode="
97 << (request.display->current_mode()
98 ? request.display->current_mode()->ToString()
99 : "nullptr (disabled)")
100 << ".";
101}
102
Daniele Castagna4f0689b2019-10-30 01:16:47103// Samples used to define buckets used by DisplayResolution enum.
104// The enum is used to record screen resolution statistics.
105const int32_t kDisplayResolutionSamples[] = {1024, 1280, 1440, 1920,
106 2560, 3840, 5120, 7680};
107
Gil Dekelc8b8c4ed2022-05-04 20:30:38108void UpdateResolutionUma(const DisplayConfigureRequest& request,
109 const std::string& uma_name) {
110 // Display is powered off.
111 if (!request.mode)
112 return;
Daniele Castagna4f0689b2019-10-30 01:16:47113
Gil Dekelc8b8c4ed2022-05-04 20:30:38114 // First, compute the index of the enum DisplayResolution.
115 // The index has to match the definition of the enum in enums.xml.
116 const uint32_t samples_list_size = std::size(kDisplayResolutionSamples);
117 const gfx::Size size = request.mode->size();
Daniele Castagna4f0689b2019-10-30 01:16:47118 uint32_t width_idx = 0;
119 uint32_t height_idx = 0;
Gil Dekelc8b8c4ed2022-05-04 20:30:38120 for (; width_idx < samples_list_size; width_idx++) {
Daniele Castagna4f0689b2019-10-30 01:16:47121 if (size.width() <= kDisplayResolutionSamples[width_idx])
122 break;
123 }
Gil Dekelc8b8c4ed2022-05-04 20:30:38124 for (; height_idx < samples_list_size; height_idx++) {
Daniele Castagna4f0689b2019-10-30 01:16:47125 if (size.height() <= kDisplayResolutionSamples[height_idx])
126 break;
127 }
128
Gil Dekelc8b8c4ed2022-05-04 20:30:38129 int display_resolution_index = 0;
130 if (width_idx == samples_list_size || height_idx == samples_list_size) {
131 // Check if we are in the overflow bucket.
132 display_resolution_index = samples_list_size * samples_list_size + 1;
133 } else {
134 // Compute the index of DisplayResolution, starting from 1, since 0 is used
135 // when powering off the display.
136 display_resolution_index = width_idx * samples_list_size + height_idx + 1;
137 }
138
139 base::UmaHistogramExactLinear(uma_name, display_resolution_index,
140 samples_list_size * samples_list_size + 2);
Daniele Castagna4f0689b2019-10-30 01:16:47141}
142
Gil Dekelc8b8c4ed2022-05-04 20:30:38143// A list of common refresh rates that are used to help fit approximate refresh
144// rate values into one of the common refresh rate bins.
145constexpr float kCommonDisplayRefreshRates[] = {
146 24.0, 25.0, 30.0, 45.0, 48.0, 50.0, 60.0, 75.0,
147 90.0, 100.0, 120.0, 144.0, 165.0, 200.0, 240.0};
Gil Dekel20dc5302020-12-01 20:03:41148
Gil Dekelc8b8c4ed2022-05-04 20:30:38149void UpdateRefreshRateUma(const DisplayConfigureRequest& request,
150 const std::string& uma_name) {
151 // Display is powered off.
152 if (!request.mode)
153 return;
Gil Dekel20dc5302020-12-01 20:03:41154
Gil Dekelc8b8c4ed2022-05-04 20:30:38155 base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
156 uma_name, base::HistogramBase::kUmaTargetedHistogramFlag);
157
158 // Check if the refresh value is within an epsilon from one of the common
159 // refresh rate values.
Gil Dekela7ca9fc2022-05-16 19:25:37160 for (float common_rate : kCommonDisplayRefreshRates) {
161 const bool is_within_epsilon = std::abs(request.mode->refresh_rate() -
162 common_rate) < kRefreshRateEpsilon;
Gil Dekelc8b8c4ed2022-05-04 20:30:38163 if (is_within_epsilon) {
Gil Dekela7ca9fc2022-05-16 19:25:37164 histogram->Add(common_rate);
Gil Dekelc8b8c4ed2022-05-04 20:30:38165 return;
166 }
167 }
168
169 // Since this is not a common refresh rate value, report it as is.
170 histogram->Add(request.mode->refresh_rate());
Gil Dekel20dc5302020-12-01 20:03:41171}
172
Gil Dekel36b941dd2021-01-23 00:37:23173void UpdateAttemptSucceededUma(
174 const std::vector<DisplayConfigureRequest>& requests,
175 bool display_success) {
176 for (const auto& request : requests) {
Gil Dekelc8b8c4ed2022-05-04 20:30:38177 const std::string uma_name_prefix = GetUmaNamePrefixForRequest(request);
178 base::UmaHistogramBoolean(uma_name_prefix + "AttemptSucceeded",
179 display_success);
Gil Dekel36b941dd2021-01-23 00:37:23180
181 VLOG(2) << "Configured status=" << display_success
182 << " display=" << request.display->display_id()
183 << " origin=" << request.origin.ToString()
Andrew Wolfers4eb4c302023-02-14 21:37:33184 << " mode=" << (request.mode ? request.mode->ToString() : "null")
185 << " enable_vrr=" << request.enable_vrr;
Gil Dekel36b941dd2021-01-23 00:37:23186 }
Gil Dekel20dc5302020-12-01 20:03:41187}
188
Gil Dekel36b941dd2021-01-23 00:37:23189void UpdateFinalStatusUma(
Gil Dekel81fc8d52023-07-26 19:40:47190 const std::vector<RequestAndStatusList>& requests_and_statuses,
191 ConfigureDisplaysTask::Status status) {
Gil Dekel20dc5302020-12-01 20:03:41192 int mst_external_displays = 0;
Gil Dekel36b941dd2021-01-23 00:37:23193 size_t total_external_displays = requests_and_statuses.size();
194 for (auto& request_and_status : requests_and_statuses) {
Gil Dekel472925e2022-05-16 18:55:27195 const DisplayConfigureRequest* request = request_and_status.first;
Gil Dekel36b941dd2021-01-23 00:37:23196
Gil Dekel20dc5302020-12-01 20:03:41197 // Is this display SST (single-stream vs. MST multi-stream).
Gil Dekel472925e2022-05-16 18:55:27198 const bool sst_display = request->display->base_connector_id() &&
199 request->display->path_topology().empty();
Gil Dekel20dc5302020-12-01 20:03:41200 if (!sst_display)
201 mst_external_displays++;
202
Gil Dekel472925e2022-05-16 18:55:27203 if (request->display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
Gil Dekel20dc5302020-12-01 20:03:41204 total_external_displays--;
205
Gil Dekel472925e2022-05-16 18:55:27206 const std::string uma_name_prefix = GetUmaNamePrefixForRequest(*request);
Gil Dekelc8b8c4ed2022-05-04 20:30:38207 if (request_and_status.second) {
Gil Dekel472925e2022-05-16 18:55:27208 UpdateResolutionUma(*request, uma_name_prefix + "Success.Resolution");
209 UpdateRefreshRateUma(*request, uma_name_prefix + "Success.RefreshRate");
Gil Dekelc8b8c4ed2022-05-04 20:30:38210 }
211 base::UmaHistogramBoolean(uma_name_prefix + "FinalStatus",
212 request_and_status.second);
Gil Dekel20dc5302020-12-01 20:03:41213 }
214
Gil Dekel81fc8d52023-07-26 19:40:47215 base::UmaHistogramEnumeration("ConfigureDisplays.Modeset.FinalTaskStatus",
216 status);
217
Gil Dekel20dc5302020-12-01 20:03:41218 base::UmaHistogramExactLinear(
219 "ConfigureDisplays.Modeset.TotalExternalDisplaysCount",
220 base::checked_cast<int>(total_external_displays), kMaxDisplaysCount);
221
222 base::UmaHistogramExactLinear(
223 "ConfigureDisplays.Modeset.MstExternalDisplaysCount",
224 mst_external_displays, kMaxDisplaysCount);
225
226 if (total_external_displays > 0) {
227 const int mst_displays_percentage =
228 100.0 * mst_external_displays / total_external_displays;
229 UMA_HISTOGRAM_PERCENTAGE(
230 "ConfigureDisplays.Modeset.MstExternalDisplaysPercentage",
231 mst_displays_percentage);
232 }
233}
234
Andrew Wolfers62440092024-08-12 18:46:08235// Updates properties of the |display| according to the given |request| after a
236// successful configuration. The display ids of |display| and |request| must
237// match.
238void UpdateSnapshotAfterConfiguration(
239 DisplaySnapshot* display,
240 const DisplayConfigurationParams& request) {
241 CHECK_EQ(display->display_id(), request.id);
242 display->set_current_mode(request.mode.get());
243 display->set_origin(request.origin);
244 if (display->IsVrrCapable()) {
245 display->set_variable_refresh_rate_state(
Andrew Wolfers56a356b2024-08-14 13:10:41246 request.enable_vrr ? VariableRefreshRateState::kVrrEnabled
247 : VariableRefreshRateState::kVrrDisabled);
Drew Davenport3e89c1b02024-05-09 22:12:08248 }
249}
250
dnicoara9372a7912014-12-11 01:29:06251} // namespace
252
253DisplayConfigureRequest::DisplayConfigureRequest(DisplaySnapshot* display,
254 const DisplayMode* mode,
Andrew Wolfers4eb4c302023-02-14 21:37:33255 const gfx::Point& origin,
256 bool enable_vrr)
Andrew Wolfers54db3092024-07-17 18:57:15257 : display(display),
258 mode(mode ? mode->Clone() : nullptr),
259 origin(origin),
260 enable_vrr(enable_vrr) {}
Andrew Wolfers4eb4c302023-02-14 21:37:33261
262DisplayConfigureRequest::DisplayConfigureRequest(DisplaySnapshot* display,
263 const DisplayMode* mode,
dnicoara9372a7912014-12-11 01:29:06264 const gfx::Point& origin)
Drew Davenport3e89c1b02024-05-09 22:12:08265 : DisplayConfigureRequest(display,
266 mode,
267 origin,
268 /*enable_vrr=*/false) {}
dnicoara9372a7912014-12-11 01:29:06269
Andrew Wolfers54db3092024-07-17 18:57:15270DisplayConfigureRequest::DisplayConfigureRequest(
271 const DisplayConfigureRequest& other)
272 : DisplayConfigureRequest(other.display,
273 other.mode.get(),
274 other.origin,
275 other.enable_vrr) {}
276
277DisplayConfigureRequest::~DisplayConfigureRequest() = default;
278
dnicoara9372a7912014-12-11 01:29:06279ConfigureDisplaysTask::ConfigureDisplaysTask(
280 NativeDisplayDelegate* delegate,
281 const std::vector<DisplayConfigureRequest>& requests,
Drew Davenport7636a462022-07-21 20:14:30282 ResponseCallback callback,
283 ConfigurationType configuration_type)
dnicoara9372a7912014-12-11 01:29:06284 : delegate_(delegate),
285 requests_(requests),
Drew Davenport7636a462022-07-21 20:14:30286 configuration_type_(configuration_type),
Sylvain Defresne23395c7a2019-10-02 10:07:45287 callback_(std::move(callback)),
Jeremy Roman47d432e2019-08-20 14:24:00288 task_status_(SUCCESS) {
afakhry4e92e8c2017-04-20 17:04:59289 delegate_->AddObserver(this);
dnicoara9372a7912014-12-11 01:29:06290}
291
Gil Dekel472925e2022-05-16 18:55:27292ConfigureDisplaysTask::RequestToOriginalMode::RequestToOriginalMode(
293 DisplayConfigureRequest* request,
294 const DisplayMode* original_mode)
Andrew Wolfers54db3092024-07-17 18:57:15295 : request(request),
296 original_mode(original_mode ? original_mode->Clone() : nullptr) {}
297
298ConfigureDisplaysTask::RequestToOriginalMode::RequestToOriginalMode(
299 const RequestToOriginalMode& other)
300 : RequestToOriginalMode(other.request, other.original_mode.get()) {}
301
302ConfigureDisplaysTask::RequestToOriginalMode::~RequestToOriginalMode() =
303 default;
Gil Dekel472925e2022-05-16 18:55:27304
afakhry4e92e8c2017-04-20 17:04:59305ConfigureDisplaysTask::~ConfigureDisplaysTask() {
306 delegate_->RemoveObserver(this);
307}
dnicoara9372a7912014-12-11 01:29:06308
309void ConfigureDisplaysTask::Run() {
Gil Dekel3369eec2020-10-06 19:53:10310 DCHECK(!requests_.empty());
dnicoara9372a7912014-12-11 01:29:06311
Gil Dekelc8b8c4ed2022-05-04 20:30:38312 const bool is_first_attempt = pending_display_group_requests_.empty();
Gil Dekel3369eec2020-10-06 19:53:10313 std::vector<display::DisplayConfigurationParams> config_requests;
314 for (const auto& request : requests_) {
Gil Dekelbbc40352021-01-05 18:33:56315 LogIfInvalidRequestForInternalDisplay(request);
316
Gil Dekel3369eec2020-10-06 19:53:10317 config_requests.emplace_back(request.display->display_id(), request.origin,
Andrew Wolfers54db3092024-07-17 18:57:15318 request.mode.get(), request.enable_vrr);
Daniele Castagna4f0689b2019-10-30 01:16:47319
Gil Dekelc8b8c4ed2022-05-04 20:30:38320 if (is_first_attempt) {
321 const std::string uma_name_prefix = GetUmaNamePrefixForRequest(request);
322 UpdateResolutionUma(request,
323 uma_name_prefix + "OriginalRequest.Resolution");
324 }
dnicoara9372a7912014-12-11 01:29:06325 }
326
Gil Dekel36b941dd2021-01-23 00:37:23327 const auto& on_configured =
Gil Dekelc8b8c4ed2022-05-04 20:30:38328 is_first_attempt ? &ConfigureDisplaysTask::OnFirstAttemptConfigured
329 : &ConfigureDisplaysTask::OnRetryConfigured;
Gil Dekel36b941dd2021-01-23 00:37:23330
Drew Davenport5686c952024-03-08 16:47:50331 display::ModesetFlags modeset_flags{display::ModesetFlag::kTestModeset};
Drew Davenport7636a462022-07-21 20:14:30332 if (configuration_type_ == kConfigurationTypeSeamless)
Drew Davenport5686c952024-03-08 16:47:50333 modeset_flags.Put(display::ModesetFlag::kSeamlessModeset);
Gil Dekel36b941dd2021-01-23 00:37:23334 delegate_->Configure(
335 config_requests,
Gil Dekelcd4c2c02022-07-19 18:01:37336 base::BindOnce(on_configured, weak_ptr_factory_.GetWeakPtr()),
Drew Davenport7636a462022-07-21 20:14:30337 modeset_flags);
dnicoara9372a7912014-12-11 01:29:06338}
339
afakhry4e92e8c2017-04-20 17:04:59340void ConfigureDisplaysTask::OnConfigurationChanged() {}
341
342void ConfigureDisplaysTask::OnDisplaySnapshotsInvalidated() {
afakhry4e92e8c2017-04-20 17:04:59343 // From now on, don't access |requests_[index]->display|; they're invalid.
344 task_status_ = ERROR;
345 weak_ptr_factory_.InvalidateWeakPtrs();
Gil Dekel3369eec2020-10-06 19:53:10346 std::move(callback_).Run(task_status_);
afakhry4e92e8c2017-04-20 17:04:59347}
348
Andrew Wolfers62440092024-08-12 18:46:08349void ConfigureDisplaysTask::OnFirstAttemptConfigured(
350 const std::vector<DisplayConfigurationParams>& request_results,
351 bool config_success) {
Gil Dekel36b941dd2021-01-23 00:37:23352 UpdateAttemptSucceededUma(requests_, config_success);
Daniele Castagna4f0689b2019-10-30 01:16:47353
Gil Dekel36b941dd2021-01-23 00:37:23354 if (!config_success) {
Gil Dekel472925e2022-05-16 18:55:27355 // Partition |requests_| into smaller groups via
356 // |pending_display_group_requests_|, update the task's state, and initiate
357 // the retry logic. The next time |delegate_|->Configure() terminates
358 // OnRetryConfigured() will be executed instead.
Gil Dekel36b941dd2021-01-23 00:37:23359 PartitionRequests();
360 DCHECK(!pending_display_group_requests_.empty());
Gil Dekel472925e2022-05-16 18:55:27361 // Prep the first group
Andrew Wolfers54db3092024-07-17 18:57:15362 for (const auto& pair : pending_display_group_requests_.front()) {
363 pair.request->mode =
364 pair.original_mode ? pair.original_mode->Clone() : nullptr;
365 }
Gil Dekel42f7aba2021-01-08 18:59:55366 task_status_ = PARTIAL_SUCCESS;
367 Run();
368 return;
dnicoara9372a7912014-12-11 01:29:06369 }
370
Gil Dekel36b941dd2021-01-23 00:37:23371 // This code execute only when the first modeset attempt fully succeeds.
Andrew Wolfers62440092024-08-12 18:46:08372 // Submit the current |requests_| for modeset. Note that |requests_| is used
373 // directly instead of |request_results|, since that is what was tested (ozone
374 // sometimes alters the resulting requests to achieve better results during
375 // mode matching).
Gil Dekel8f7fa0182022-07-22 17:45:14376 std::vector<display::DisplayConfigurationParams> config_requests;
377 for (const auto& request : requests_) {
378 final_requests_status_.emplace_back(&request, true);
379
380 config_requests.emplace_back(request.display->display_id(), request.origin,
Andrew Wolfers54db3092024-07-17 18:57:15381 request.mode.get(), request.enable_vrr);
Gil Dekel36b941dd2021-01-23 00:37:23382 }
Gil Dekel788edb62020-11-25 23:41:28383
Drew Davenport5686c952024-03-08 16:47:50384 display::ModesetFlags modeset_flags{display::ModesetFlag::kCommitModeset};
Gil Dekel8f7fa0182022-07-22 17:45:14385 if (configuration_type_ == kConfigurationTypeSeamless)
Drew Davenport5686c952024-03-08 16:47:50386 modeset_flags.Put(display::ModesetFlag::kSeamlessModeset);
Gil Dekel8f7fa0182022-07-22 17:45:14387 delegate_->Configure(config_requests,
388 base::BindOnce(&ConfigureDisplaysTask::OnConfigured,
389 weak_ptr_factory_.GetWeakPtr()),
390 modeset_flags);
dnicoara9372a7912014-12-11 01:29:06391}
392
Andrew Wolfers62440092024-08-12 18:46:08393void ConfigureDisplaysTask::OnRetryConfigured(
394 const std::vector<DisplayConfigurationParams>& request_results,
395 bool config_success) {
Gil Dekel36b941dd2021-01-23 00:37:23396 UpdateAttemptSucceededUma(requests_, config_success);
397
398 if (!config_success) {
399 // If one of the largest display request can be downgraded, try again.
400 // Otherwise this configuration task is a failure.
Gil Dekel472925e2022-05-16 18:55:27401 if (DowngradeDisplayRequestGroup()) {
Gil Dekel36b941dd2021-01-23 00:37:23402 Run();
403 return;
404 } else {
Gil Dekel472925e2022-05-16 18:55:27405 // Disable all displays in the current group, since we failed to find an
406 // alternative mode. Note that we skip modeset if the latest (or a
407 // single) pending group fails. There is no point in disabling displays
408 // that are already disabled from previous attempts and failed to change
409 // mode.
Andrew Wolfers54db3092024-07-17 18:57:15410 for (const auto& pair : pending_display_group_requests_.front()) {
411 pair.request->mode.reset();
412 }
Gil Dekel36b941dd2021-01-23 00:37:23413 task_status_ = ERROR;
414 }
Gil Dekel8f7fa0182022-07-22 17:45:14415 } else {
Andrew Wolfers62440092024-08-12 18:46:08416 // This configuration attempt passed test-modeset. Cache |requests_| so we
417 // can use it to modeset the displays once we are done testing, or if no
418 // other future attempts succeed. Note that |requests_| is used directly
419 // instead of |request_results|, since that is what was tested (ozone
420 // sometimes alters the resulting requests to achieve better results during
421 // mode matching).
Gil Dekel8f7fa0182022-07-22 17:45:14422 last_successful_config_parameters_.clear();
423 for (const auto& request : requests_) {
424 last_successful_config_parameters_.emplace_back(
Andrew Wolfers54db3092024-07-17 18:57:15425 request.display->display_id(), request.origin, request.mode.get(),
Andrew Wolfers4eb4c302023-02-14 21:37:33426 request.enable_vrr);
Gil Dekel8f7fa0182022-07-22 17:45:14427 }
Gil Dekel36b941dd2021-01-23 00:37:23428 }
429
430 // This code executes only when this display group request fully succeeds or
431 // fails to modeset. Update the final status of this group.
Gil Dekel8f7fa0182022-07-22 17:45:14432 for (const auto& pair : pending_display_group_requests_.front())
433 final_requests_status_.emplace_back(pair.request, config_success);
Gil Dekel36b941dd2021-01-23 00:37:23434
435 // Subsequent modeset attempts will be done on the next pending display group,
436 // if one exists.
437 pending_display_group_requests_.pop();
Gil Dekel36b941dd2021-01-23 00:37:23438 if (!pending_display_group_requests_.empty()) {
Gil Dekel472925e2022-05-16 18:55:27439 // Prep the next group
Andrew Wolfers54db3092024-07-17 18:57:15440 for (const auto& pair : pending_display_group_requests_.front()) {
441 pair.request->mode =
442 pair.original_mode ? pair.original_mode->Clone() : nullptr;
443 }
Gil Dekel36b941dd2021-01-23 00:37:23444 Run();
445 return;
446 }
447
Gil Dekel8f7fa0182022-07-22 17:45:14448 if (task_status_ == ERROR) {
449 LOG(WARNING) << "One or more of the connected display groups failed to "
450 "pass test-modeset entirely and will be disabled.";
451
452 if (last_successful_config_parameters_.empty()) {
453 LOG(ERROR) << "Display configuration failed. No modeset was attempted.";
454
Gil Dekel81fc8d52023-07-26 19:40:47455 UpdateFinalStatusUma(final_requests_status_, task_status_);
Gil Dekel8f7fa0182022-07-22 17:45:14456 std::move(callback_).Run(task_status_);
457 return;
458 }
459 }
460
461 // Configure the displays using the last successful configuration parameter
462 // list.
Drew Davenport5686c952024-03-08 16:47:50463 display::ModesetFlags modeset_flags{display::ModesetFlag::kCommitModeset};
Gil Dekel8f7fa0182022-07-22 17:45:14464 if (configuration_type_ == kConfigurationTypeSeamless)
Drew Davenport5686c952024-03-08 16:47:50465 modeset_flags.Put(display::ModesetFlag::kSeamlessModeset);
Gil Dekel8f7fa0182022-07-22 17:45:14466 delegate_->Configure(last_successful_config_parameters_,
467 base::BindOnce(&ConfigureDisplaysTask::OnConfigured,
468 weak_ptr_factory_.GetWeakPtr()),
469 modeset_flags);
470}
471
Andrew Wolfers62440092024-08-12 18:46:08472void ConfigureDisplaysTask::OnConfigured(
473 const std::vector<DisplayConfigurationParams>& request_results,
474 bool config_success) {
Gil Dekel8f7fa0182022-07-22 17:45:14475 if (config_success) {
Andrew Wolfers62440092024-08-12 18:46:08476 base::flat_map<int64_t, DisplaySnapshot*> snapshot_map;
Gil Dekel8f7fa0182022-07-22 17:45:14477 for (const DisplayConfigureRequest& request : requests_) {
Andrew Wolfers62440092024-08-12 18:46:08478 snapshot_map.emplace(request.display->display_id(), request.display);
479 }
480 // Use |request_results| to update the snapshots.
481 for (const DisplayConfigurationParams& request : request_results) {
482 const auto it = snapshot_map.find(request.id);
483 CHECK(it != snapshot_map.end());
484 UpdateSnapshotAfterConfiguration(it->second, request);
Gil Dekel8f7fa0182022-07-22 17:45:14485 }
486 }
487
Gil Dekel81fc8d52023-07-26 19:40:47488 UpdateFinalStatusUma(final_requests_status_, task_status_);
Gil Dekel36b941dd2021-01-23 00:37:23489 std::move(callback_).Run(task_status_);
490}
491
492void ConfigureDisplaysTask::PartitionRequests() {
493 pending_display_group_requests_ = PartitionedRequestsQueue();
Gil Dekel36b941dd2021-01-23 00:37:23494
Mark Yacoub100f2df2022-04-19 18:01:14495 base::flat_set<uint64_t> handled_connectors;
Gil Dekel36b941dd2021-01-23 00:37:23496 for (size_t i = 0; i < requests_.size(); ++i) {
497 uint64_t connector_id = requests_[i].display->base_connector_id();
498 if (handled_connectors.find(connector_id) != handled_connectors.end())
499 continue;
500
Gil Dekel472925e2022-05-16 18:55:27501 std::vector<ConfigureDisplaysTask::RequestToOriginalMode> request_group;
Gil Dekel36b941dd2021-01-23 00:37:23502 for (size_t j = i; j < requests_.size(); ++j) {
Gil Dekel472925e2022-05-16 18:55:27503 if (connector_id == requests_[j].display->base_connector_id()) {
504 // Disable all requests in preparation increment connector retries after
505 // mapping them to their original request.
Andrew Wolfers54db3092024-07-17 18:57:15506 request_group.emplace_back(&requests_[j], requests_[j].mode.get());
507 requests_[j].mode.reset();
Gil Dekel472925e2022-05-16 18:55:27508 }
Gil Dekel36b941dd2021-01-23 00:37:23509 }
510
Gil Dekel36b941dd2021-01-23 00:37:23511 handled_connectors.insert(connector_id);
Mark Yacoub100f2df2022-04-19 18:01:14512 pending_display_group_requests_.push(request_group);
Gil Dekel36b941dd2021-01-23 00:37:23513 }
514}
515
Gil Dekel472925e2022-05-16 18:55:27516bool ConfigureDisplaysTask::DowngradeDisplayRequestGroup() {
Gil Dekel36b941dd2021-01-23 00:37:23517 auto cmp = [](DisplayConfigureRequest* lhs, DisplayConfigureRequest* rhs) {
518 return *lhs->mode < *rhs->mode;
519 };
520 std::priority_queue<DisplayConfigureRequest*,
521 std::vector<DisplayConfigureRequest*>, decltype(cmp)>
522 sorted_requests(cmp);
523
Gil Dekel472925e2022-05-16 18:55:27524 for (const auto& pair : pending_display_group_requests_.front()) {
525 if (pair.request->display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
Gil Dekel36b941dd2021-01-23 00:37:23526 continue;
527
Gil Dekel472925e2022-05-16 18:55:27528 if (!pair.request->mode)
Gil Dekel36b941dd2021-01-23 00:37:23529 continue;
530
Gil Dekel472925e2022-05-16 18:55:27531 sorted_requests.push(pair.request);
Gil Dekel36b941dd2021-01-23 00:37:23532 }
533
534 // Fail if there are no viable candidates to downgrade
535 if (sorted_requests.empty())
536 return false;
537
538 while (!sorted_requests.empty()) {
539 DisplayConfigureRequest* next_request = sorted_requests.top();
540 sorted_requests.pop();
541
Gil Dekel66a97bc2022-04-29 04:21:50542 const DisplayMode* next_mode = FindNextMode(*next_request);
Gil Dekel36b941dd2021-01-23 00:37:23543 if (next_mode) {
Andrew Wolfers54db3092024-07-17 18:57:15544 next_request->mode = next_mode->Clone();
Gil Dekel36b941dd2021-01-23 00:37:23545 return true;
546 }
547 }
548
549 return false;
550}
551
kylechar7a067ec2017-01-07 01:16:28552} // namespace display