blob: 57eba9997e426b9f0b38655667d9955d1d0d3fba [file] [log] [blame]
dnicoara9372a7912014-12-11 01:29:061// Copyright 2014 The Chromium Authors. All rights reserved.
2// 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
7#include "base/auto_reset.h"
8#include "base/bind.h"
Brett Wilsonb02c0a22017-09-25 22:34:429#include "base/containers/queue.h"
Hans Wennborg3930cf32020-06-17 16:29:5210#include "base/logging.h"
Daniele Castagna4f0689b2019-10-30 01:16:4711#include "base/metrics/histogram_functions.h"
12#include "base/stl_util.h"
Joone Hurd3ae8732018-04-17 18:05:0913#include "ui/display/manager/display_util.h"
Mark Yacoubd18a2922020-07-07 01:14:1514#include "ui/display/types/display_configuration_params.h"
dnicoara9372a7912014-12-11 01:29:0615#include "ui/display/types/display_snapshot.h"
16#include "ui/display/types/native_display_delegate.h"
17
kylechar7a067ec2017-01-07 01:16:2818namespace display {
dnicoara9372a7912014-12-11 01:29:0619
20namespace {
21
22// Find the next best mode after |display_mode|. If none can be found return
23// nullptr.
24const DisplayMode* FindNextMode(const DisplaySnapshot& display_state,
dnicoaraa89c2082015-01-05 16:49:0625 const DisplayMode* display_mode) {
26 if (!display_mode)
27 return nullptr;
28
dnicoara9372a7912014-12-11 01:29:0629 int best_mode_pixels = 0;
30 const DisplayMode* best_mode = nullptr;
dnicoaraa89c2082015-01-05 16:49:0631 int current_mode_pixels = display_mode->size().GetArea();
dbasehore01e90042016-05-27 06:16:5132 for (const std::unique_ptr<const DisplayMode>& mode : display_state.modes()) {
dnicoara9372a7912014-12-11 01:29:0633 int pixel_count = mode->size().GetArea();
34 if (pixel_count < current_mode_pixels && pixel_count > best_mode_pixels) {
dbasehore01e90042016-05-27 06:16:5135 best_mode = mode.get();
dnicoara9372a7912014-12-11 01:29:0636 best_mode_pixels = pixel_count;
37 }
38 }
39
40 return best_mode;
41}
42
Daniele Castagna4f0689b2019-10-30 01:16:4743// Samples used to define buckets used by DisplayResolution enum.
44// The enum is used to record screen resolution statistics.
45const int32_t kDisplayResolutionSamples[] = {1024, 1280, 1440, 1920,
46 2560, 3840, 5120, 7680};
47
48// Computes the index of the enum DisplayResolution.
49// The index has to match the definition of the enum in enums.xml
50int ComputeDisplayResolutionEnum(const DisplayMode* mode) {
51 if (!mode)
52 return 0; // Display is powered off
53
54 const gfx::Size size = mode->size();
55 uint32_t width_idx = 0;
56 uint32_t height_idx = 0;
57 for (; width_idx < base::size(kDisplayResolutionSamples); width_idx++) {
58 if (size.width() <= kDisplayResolutionSamples[width_idx])
59 break;
60 }
61 for (; height_idx < base::size(kDisplayResolutionSamples); height_idx++) {
62 if (size.height() <= kDisplayResolutionSamples[height_idx])
63 break;
64 }
65
66 if (width_idx == base::size(kDisplayResolutionSamples) ||
67 height_idx == base::size(kDisplayResolutionSamples))
68 return base::size(kDisplayResolutionSamples) *
69 base::size(kDisplayResolutionSamples) +
70 1; // Overflow bucket
71 // Computes the index of DisplayResolution, starting from 1, since 0 is used
72 // when powering off the display.
73 return width_idx * base::size(kDisplayResolutionSamples) + height_idx + 1;
74}
75
Mark Yacoub214f0dd02020-07-17 00:07:4476std::__wrap_iter<const DisplayConfigureRequest*> GetRequestForDisplayId(
77 int64_t display_id,
78 const std::vector<DisplayConfigureRequest>& requests) {
79 return find_if(requests.begin(), requests.end(),
80 [display_id](const DisplayConfigureRequest& request) {
81 return request.display->display_id() == display_id;
82 });
83}
84
dnicoara9372a7912014-12-11 01:29:0685} // namespace
86
87DisplayConfigureRequest::DisplayConfigureRequest(DisplaySnapshot* display,
88 const DisplayMode* mode,
89 const gfx::Point& origin)
kylechar731f85f92016-12-01 20:50:4690 : display(display), mode(mode), origin(origin) {}
dnicoara9372a7912014-12-11 01:29:0691
92ConfigureDisplaysTask::ConfigureDisplaysTask(
93 NativeDisplayDelegate* delegate,
94 const std::vector<DisplayConfigureRequest>& requests,
Sylvain Defresne23395c7a2019-10-02 10:07:4595 ResponseCallback callback)
dnicoara9372a7912014-12-11 01:29:0696 : delegate_(delegate),
97 requests_(requests),
Sylvain Defresne23395c7a2019-10-02 10:07:4598 callback_(std::move(callback)),
Jeremy Roman47d432e2019-08-20 14:24:0099 task_status_(SUCCESS) {
afakhry4e92e8c2017-04-20 17:04:59100 delegate_->AddObserver(this);
dnicoara9372a7912014-12-11 01:29:06101}
102
afakhry4e92e8c2017-04-20 17:04:59103ConfigureDisplaysTask::~ConfigureDisplaysTask() {
104 delegate_->RemoveObserver(this);
105}
dnicoara9372a7912014-12-11 01:29:06106
107void ConfigureDisplaysTask::Run() {
Gil Dekel3369eec2020-10-06 19:53:10108 DCHECK(!requests_.empty());
dnicoara9372a7912014-12-11 01:29:06109
Gil Dekel3369eec2020-10-06 19:53:10110 std::vector<display::DisplayConfigurationParams> config_requests;
111 for (const auto& request : requests_) {
112 config_requests.emplace_back(request.display->display_id(), request.origin,
113 request.mode);
Daniele Castagna4f0689b2019-10-30 01:16:47114
Gil Dekel3369eec2020-10-06 19:53:10115 const bool internal =
116 request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
117 base::UmaHistogramExactLinear(
118 internal ? "ConfigureDisplays.Internal.Modeset.Resolution"
119 : "ConfigureDisplays.External.Modeset.Resolution",
120 ComputeDisplayResolutionEnum(request.mode),
121 base::size(kDisplayResolutionSamples) *
122 base::size(kDisplayResolutionSamples) +
123 2);
124 base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
125 internal ? "ConfigureDisplays.Internal.Modeset.RefreshRate"
126 : "ConfigureDisplays.External.Modeset.RefreshRate",
127 1, 240, 18, base::HistogramBase::kUmaTargetedHistogramFlag);
128 histogram->Add(request.mode ? std::round(request.mode->refresh_rate()) : 0);
dnicoara9372a7912014-12-11 01:29:06129 }
130
Gil Dekel3369eec2020-10-06 19:53:10131 delegate_->Configure(config_requests,
132 base::BindOnce(&ConfigureDisplaysTask::OnConfigured,
133 weak_ptr_factory_.GetWeakPtr()));
dnicoara9372a7912014-12-11 01:29:06134}
135
afakhry4e92e8c2017-04-20 17:04:59136void ConfigureDisplaysTask::OnConfigurationChanged() {}
137
138void ConfigureDisplaysTask::OnDisplaySnapshotsInvalidated() {
afakhry4e92e8c2017-04-20 17:04:59139 // From now on, don't access |requests_[index]->display|; they're invalid.
140 task_status_ = ERROR;
141 weak_ptr_factory_.InvalidateWeakPtrs();
Gil Dekel3369eec2020-10-06 19:53:10142 std::move(callback_).Run(task_status_);
afakhry4e92e8c2017-04-20 17:04:59143}
144
Mark Yacoub214f0dd02020-07-17 00:07:44145void ConfigureDisplaysTask::OnConfigured(
146 const base::flat_map<int64_t, bool>& statuses) {
147 bool config_success = true;
Mark Yacoub214f0dd02020-07-17 00:07:44148 // Check if all displays are successfully configured.
149 for (const auto& status : statuses) {
150 int64_t display_id = status.first;
151 bool display_success = status.second;
152 config_success &= display_success;
Daniele Castagna4f0689b2019-10-30 01:16:47153
Mark Yacoub214f0dd02020-07-17 00:07:44154 auto request = GetRequestForDisplayId(display_id, requests_);
155 DCHECK(request != requests_.end());
156
157 VLOG(2) << "Configured status=" << display_success
158 << " display=" << request->display->display_id()
159 << " origin=" << request->origin.ToString()
160 << " mode=" << (request->mode ? request->mode->ToString() : "null");
161
162 bool internal =
163 request->display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
164 base::UmaHistogramBoolean(
165 internal ? "ConfigureDisplays.Internal.Modeset.AttemptSucceeded"
166 : "ConfigureDisplays.External.Modeset.AttemptSucceeded",
167 display_success);
168 }
169
Gil Dekel3369eec2020-10-06 19:53:10170 // Update displays upon success or prep |requests_| for reconfiguration.
Mark Yacoub214f0dd02020-07-17 00:07:44171 if (config_success) {
Gil Dekel3369eec2020-10-06 19:53:10172 for (auto& request : requests_) {
173 request.display->set_current_mode(request.mode);
174 request.display->set_origin(request.origin);
Mark Yacoub214f0dd02020-07-17 00:07:44175 }
176 } else {
177 bool should_reconfigure = false;
178 // For the failing config, check if there is another mode to be requested.
179 // If there is one, attempt to reconfigure everything again.
180 for (const auto& status : statuses) {
181 int64_t display_id = status.first;
182 bool display_success = status.second;
183 if (!display_success) {
184 const DisplayConfigureRequest* request =
185 GetRequestForDisplayId(display_id, requests_).base();
Mark Yacoubd8a32382020-09-18 19:27:55186 const DisplayMode* next_mode =
Mark Yacoub214f0dd02020-07-17 00:07:44187 FindNextMode(*request->display, request->mode);
Mark Yacoubd8a32382020-09-18 19:27:55188 if (next_mode) {
189 const_cast<DisplayConfigureRequest*>(request)->mode = next_mode;
190 should_reconfigure = true;
191 }
Mark Yacoub214f0dd02020-07-17 00:07:44192 }
193 }
Mark Yacoub214f0dd02020-07-17 00:07:44194 if (should_reconfigure) {
Gil Dekel3369eec2020-10-06 19:53:10195 task_status_ = PARTIAL_SUCCESS;
dnicoara9372a7912014-12-11 01:29:06196 Run();
197 return;
198 }
dnicoara9372a7912014-12-11 01:29:06199 }
200
Gil Dekel3369eec2020-10-06 19:53:10201 // Update the final state.
202 for (auto& request : requests_) {
203 bool internal = request.display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
Mark Yacoub214f0dd02020-07-17 00:07:44204 base::UmaHistogramBoolean(
205 internal ? "ConfigureDisplays.Internal.Modeset.FinalStatus"
206 : "ConfigureDisplays.External.Modeset.FinalStatus",
207 config_success);
208 }
Daniele Castagna4f0689b2019-10-30 01:16:47209
Mark Yacoub214f0dd02020-07-17 00:07:44210 if (!config_success)
dnicoara9372a7912014-12-11 01:29:06211 task_status_ = ERROR;
Gil Dekel3369eec2020-10-06 19:53:10212 std::move(callback_).Run(task_status_);
dnicoara9372a7912014-12-11 01:29:06213}
214
kylechar7a067ec2017-01-07 01:16:28215} // namespace display