blob: 52e232e8f253f16c94481f3ba6ae41a73de3ba32 [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
dnicoara9372a7912014-12-11 01:29:0676} // namespace
77
78DisplayConfigureRequest::DisplayConfigureRequest(DisplaySnapshot* display,
79 const DisplayMode* mode,
80 const gfx::Point& origin)
kylechar731f85f92016-12-01 20:50:4681 : display(display), mode(mode), origin(origin) {}
dnicoara9372a7912014-12-11 01:29:0682
83ConfigureDisplaysTask::ConfigureDisplaysTask(
84 NativeDisplayDelegate* delegate,
85 const std::vector<DisplayConfigureRequest>& requests,
Sylvain Defresne23395c7a2019-10-02 10:07:4586 ResponseCallback callback)
dnicoara9372a7912014-12-11 01:29:0687 : delegate_(delegate),
88 requests_(requests),
Sylvain Defresne23395c7a2019-10-02 10:07:4589 callback_(std::move(callback)),
dnicoara9372a7912014-12-11 01:29:0690 is_configuring_(false),
91 num_displays_configured_(0),
Jeremy Roman47d432e2019-08-20 14:24:0092 task_status_(SUCCESS) {
dnicoara9372a7912014-12-11 01:29:0693 for (size_t i = 0; i < requests_.size(); ++i)
94 pending_request_indexes_.push(i);
afakhry4e92e8c2017-04-20 17:04:5995 delegate_->AddObserver(this);
dnicoara9372a7912014-12-11 01:29:0696}
97
afakhry4e92e8c2017-04-20 17:04:5998ConfigureDisplaysTask::~ConfigureDisplaysTask() {
99 delegate_->RemoveObserver(this);
100}
dnicoara9372a7912014-12-11 01:29:06101
102void ConfigureDisplaysTask::Run() {
103 // Synchronous configurators will recursively call Run(). In that case just
104 // defer their call to the next iteration in the while-loop. This is done to
105 // guard against stack overflows if the display has a large list of broken
106 // modes.
107 if (is_configuring_)
108 return;
109
dnicoara65d9d312014-12-13 02:30:47110 {
111 base::AutoReset<bool> recursivity_guard(&is_configuring_, true);
112 while (!pending_request_indexes_.empty()) {
113 size_t index = pending_request_indexes_.front();
114 DisplayConfigureRequest* request = &requests_[index];
115 pending_request_indexes_.pop();
Daniele Castagna4f0689b2019-10-30 01:16:47116 const bool internal =
117 request->display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
118 base::UmaHistogramExactLinear(
119 internal ? "ConfigureDisplays.Internal.Modeset.Resolution"
120 : "ConfigureDisplays.External.Modeset.Resolution",
121 ComputeDisplayResolutionEnum(request->mode),
122 base::size(kDisplayResolutionSamples) *
123 base::size(kDisplayResolutionSamples) +
124 2);
125
126 base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
127 internal ? "ConfigureDisplays.Internal.Modeset.RefreshRate"
128 : "ConfigureDisplays.External.Modeset.RefreshRate",
129 1, 240, 18, base::HistogramBase::kUmaTargetedHistogramFlag);
130 histogram->Add(request->mode ? std::round(request->mode->refresh_rate())
131 : 0);
132
Mark Yacoubd18a2922020-07-07 01:14:15133 display::DisplayConfigurationParams display_config_params(
134 request->display->display_id(), request->origin, request->mode);
Sylvain Defresne23395c7a2019-10-02 10:07:45135 delegate_->Configure(
Mark Yacoubd18a2922020-07-07 01:14:15136 display_config_params,
Sylvain Defresne23395c7a2019-10-02 10:07:45137 base::BindOnce(&ConfigureDisplaysTask::OnConfigured,
138 weak_ptr_factory_.GetWeakPtr(), index));
dnicoara65d9d312014-12-13 02:30:47139 }
dnicoara9372a7912014-12-11 01:29:06140 }
141
dnicoara65d9d312014-12-13 02:30:47142 // Nothing should be modified after the |callback_| is called since the
dnicoara9372a7912014-12-11 01:29:06143 // task may be deleted in the callback.
144 if (num_displays_configured_ == requests_.size())
Sylvain Defresne23395c7a2019-10-02 10:07:45145 std::move(callback_).Run(task_status_);
dnicoara9372a7912014-12-11 01:29:06146}
147
afakhry4e92e8c2017-04-20 17:04:59148void ConfigureDisplaysTask::OnConfigurationChanged() {}
149
150void ConfigureDisplaysTask::OnDisplaySnapshotsInvalidated() {
Brett Wilsonb02c0a22017-09-25 22:34:42151 base::queue<size_t> empty_queue;
afakhry4e92e8c2017-04-20 17:04:59152 pending_request_indexes_.swap(empty_queue);
153 // From now on, don't access |requests_[index]->display|; they're invalid.
154 task_status_ = ERROR;
155 weak_ptr_factory_.InvalidateWeakPtrs();
156 Run();
157}
158
dnicoara9372a7912014-12-11 01:29:06159void ConfigureDisplaysTask::OnConfigured(size_t index, bool success) {
160 DisplayConfigureRequest* request = &requests_[index];
161 VLOG(2) << "Configured status=" << success
162 << " display=" << request->display->display_id()
163 << " origin=" << request->origin.ToString()
164 << " mode=" << (request->mode ? request->mode->ToString() : "null");
Daniele Castagna4f0689b2019-10-30 01:16:47165
166 const bool internal =
167 request->display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
168 base::UmaHistogramBoolean(
169 internal ? "ConfigureDisplays.Internal.Modeset.AttemptSucceeded"
170 : "ConfigureDisplays.External.Modeset.AttemptSucceeded",
171 success);
172
dnicoara9372a7912014-12-11 01:29:06173 if (!success) {
dnicoaraa89c2082015-01-05 16:49:06174 request->mode = FindNextMode(*request->display, request->mode);
dnicoara9372a7912014-12-11 01:29:06175 if (request->mode) {
176 pending_request_indexes_.push(index);
177 if (task_status_ == SUCCESS)
178 task_status_ = PARTIAL_SUCCESS;
179
180 Run();
181 return;
182 }
183 } else {
184 request->display->set_current_mode(request->mode);
185 request->display->set_origin(request->origin);
186 }
187
188 num_displays_configured_++;
Daniele Castagna4f0689b2019-10-30 01:16:47189
190 base::UmaHistogramBoolean(
191 internal ? "ConfigureDisplays.Internal.Modeset.FinalStatus"
192 : "ConfigureDisplays.External.Modeset.FinalStatus",
193 success);
dnicoara9372a7912014-12-11 01:29:06194 if (!success)
195 task_status_ = ERROR;
196
197 Run();
198}
199
kylechar7a067ec2017-01-07 01:16:28200} // namespace display