blob: 1b37056d62ca9418ebcb82b7f93798b6a8083991 [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"
Daniele Castagna4f0689b2019-10-30 01:16:4710#include "base/metrics/histogram_functions.h"
11#include "base/stl_util.h"
Joone Hurd3ae8732018-04-17 18:05:0912#include "ui/display/manager/display_util.h"
dnicoara9372a7912014-12-11 01:29:0613#include "ui/display/types/display_snapshot.h"
14#include "ui/display/types/native_display_delegate.h"
15
kylechar7a067ec2017-01-07 01:16:2816namespace display {
dnicoara9372a7912014-12-11 01:29:0617
18namespace {
19
20// Find the next best mode after |display_mode|. If none can be found return
21// nullptr.
22const DisplayMode* FindNextMode(const DisplaySnapshot& display_state,
dnicoaraa89c2082015-01-05 16:49:0623 const DisplayMode* display_mode) {
24 if (!display_mode)
25 return nullptr;
26
dnicoara9372a7912014-12-11 01:29:0627 int best_mode_pixels = 0;
28 const DisplayMode* best_mode = nullptr;
dnicoaraa89c2082015-01-05 16:49:0629 int current_mode_pixels = display_mode->size().GetArea();
dbasehore01e90042016-05-27 06:16:5130 for (const std::unique_ptr<const DisplayMode>& mode : display_state.modes()) {
dnicoara9372a7912014-12-11 01:29:0631 int pixel_count = mode->size().GetArea();
32 if (pixel_count < current_mode_pixels && pixel_count > best_mode_pixels) {
dbasehore01e90042016-05-27 06:16:5133 best_mode = mode.get();
dnicoara9372a7912014-12-11 01:29:0634 best_mode_pixels = pixel_count;
35 }
36 }
37
38 return best_mode;
39}
40
Daniele Castagna4f0689b2019-10-30 01:16:4741// Samples used to define buckets used by DisplayResolution enum.
42// The enum is used to record screen resolution statistics.
43const int32_t kDisplayResolutionSamples[] = {1024, 1280, 1440, 1920,
44 2560, 3840, 5120, 7680};
45
46// Computes the index of the enum DisplayResolution.
47// The index has to match the definition of the enum in enums.xml
48int ComputeDisplayResolutionEnum(const DisplayMode* mode) {
49 if (!mode)
50 return 0; // Display is powered off
51
52 const gfx::Size size = mode->size();
53 uint32_t width_idx = 0;
54 uint32_t height_idx = 0;
55 for (; width_idx < base::size(kDisplayResolutionSamples); width_idx++) {
56 if (size.width() <= kDisplayResolutionSamples[width_idx])
57 break;
58 }
59 for (; height_idx < base::size(kDisplayResolutionSamples); height_idx++) {
60 if (size.height() <= kDisplayResolutionSamples[height_idx])
61 break;
62 }
63
64 if (width_idx == base::size(kDisplayResolutionSamples) ||
65 height_idx == base::size(kDisplayResolutionSamples))
66 return base::size(kDisplayResolutionSamples) *
67 base::size(kDisplayResolutionSamples) +
68 1; // Overflow bucket
69 // Computes the index of DisplayResolution, starting from 1, since 0 is used
70 // when powering off the display.
71 return width_idx * base::size(kDisplayResolutionSamples) + height_idx + 1;
72}
73
dnicoara9372a7912014-12-11 01:29:0674} // namespace
75
76DisplayConfigureRequest::DisplayConfigureRequest(DisplaySnapshot* display,
77 const DisplayMode* mode,
78 const gfx::Point& origin)
kylechar731f85f92016-12-01 20:50:4679 : display(display), mode(mode), origin(origin) {}
dnicoara9372a7912014-12-11 01:29:0680
81ConfigureDisplaysTask::ConfigureDisplaysTask(
82 NativeDisplayDelegate* delegate,
83 const std::vector<DisplayConfigureRequest>& requests,
Sylvain Defresne23395c7a2019-10-02 10:07:4584 ResponseCallback callback)
dnicoara9372a7912014-12-11 01:29:0685 : delegate_(delegate),
86 requests_(requests),
Sylvain Defresne23395c7a2019-10-02 10:07:4587 callback_(std::move(callback)),
dnicoara9372a7912014-12-11 01:29:0688 is_configuring_(false),
89 num_displays_configured_(0),
Jeremy Roman47d432e2019-08-20 14:24:0090 task_status_(SUCCESS) {
dnicoara9372a7912014-12-11 01:29:0691 for (size_t i = 0; i < requests_.size(); ++i)
92 pending_request_indexes_.push(i);
afakhry4e92e8c2017-04-20 17:04:5993 delegate_->AddObserver(this);
dnicoara9372a7912014-12-11 01:29:0694}
95
afakhry4e92e8c2017-04-20 17:04:5996ConfigureDisplaysTask::~ConfigureDisplaysTask() {
97 delegate_->RemoveObserver(this);
98}
dnicoara9372a7912014-12-11 01:29:0699
100void ConfigureDisplaysTask::Run() {
101 // Synchronous configurators will recursively call Run(). In that case just
102 // defer their call to the next iteration in the while-loop. This is done to
103 // guard against stack overflows if the display has a large list of broken
104 // modes.
105 if (is_configuring_)
106 return;
107
dnicoara65d9d312014-12-13 02:30:47108 {
109 base::AutoReset<bool> recursivity_guard(&is_configuring_, true);
110 while (!pending_request_indexes_.empty()) {
111 size_t index = pending_request_indexes_.front();
112 DisplayConfigureRequest* request = &requests_[index];
113 pending_request_indexes_.pop();
Daniele Castagna4f0689b2019-10-30 01:16:47114 const bool internal =
115 request->display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
116 base::UmaHistogramExactLinear(
117 internal ? "ConfigureDisplays.Internal.Modeset.Resolution"
118 : "ConfigureDisplays.External.Modeset.Resolution",
119 ComputeDisplayResolutionEnum(request->mode),
120 base::size(kDisplayResolutionSamples) *
121 base::size(kDisplayResolutionSamples) +
122 2);
123
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())
129 : 0);
130
Sylvain Defresne23395c7a2019-10-02 10:07:45131 delegate_->Configure(
132 *request->display, request->mode, request->origin,
133 base::BindOnce(&ConfigureDisplaysTask::OnConfigured,
134 weak_ptr_factory_.GetWeakPtr(), index));
dnicoara65d9d312014-12-13 02:30:47135 }
dnicoara9372a7912014-12-11 01:29:06136 }
137
dnicoara65d9d312014-12-13 02:30:47138 // Nothing should be modified after the |callback_| is called since the
dnicoara9372a7912014-12-11 01:29:06139 // task may be deleted in the callback.
140 if (num_displays_configured_ == requests_.size())
Sylvain Defresne23395c7a2019-10-02 10:07:45141 std::move(callback_).Run(task_status_);
dnicoara9372a7912014-12-11 01:29:06142}
143
afakhry4e92e8c2017-04-20 17:04:59144void ConfigureDisplaysTask::OnConfigurationChanged() {}
145
146void ConfigureDisplaysTask::OnDisplaySnapshotsInvalidated() {
Brett Wilsonb02c0a22017-09-25 22:34:42147 base::queue<size_t> empty_queue;
afakhry4e92e8c2017-04-20 17:04:59148 pending_request_indexes_.swap(empty_queue);
149 // From now on, don't access |requests_[index]->display|; they're invalid.
150 task_status_ = ERROR;
151 weak_ptr_factory_.InvalidateWeakPtrs();
152 Run();
153}
154
dnicoara9372a7912014-12-11 01:29:06155void ConfigureDisplaysTask::OnConfigured(size_t index, bool success) {
156 DisplayConfigureRequest* request = &requests_[index];
157 VLOG(2) << "Configured status=" << success
158 << " display=" << request->display->display_id()
159 << " origin=" << request->origin.ToString()
160 << " mode=" << (request->mode ? request->mode->ToString() : "null");
Daniele Castagna4f0689b2019-10-30 01:16:47161
162 const 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 success);
168
dnicoara9372a7912014-12-11 01:29:06169 if (!success) {
dnicoaraa89c2082015-01-05 16:49:06170 request->mode = FindNextMode(*request->display, request->mode);
dnicoara9372a7912014-12-11 01:29:06171 if (request->mode) {
172 pending_request_indexes_.push(index);
173 if (task_status_ == SUCCESS)
174 task_status_ = PARTIAL_SUCCESS;
175
176 Run();
177 return;
178 }
179 } else {
180 request->display->set_current_mode(request->mode);
181 request->display->set_origin(request->origin);
182 }
183
184 num_displays_configured_++;
Daniele Castagna4f0689b2019-10-30 01:16:47185
186 base::UmaHistogramBoolean(
187 internal ? "ConfigureDisplays.Internal.Modeset.FinalStatus"
188 : "ConfigureDisplays.External.Modeset.FinalStatus",
189 success);
dnicoara9372a7912014-12-11 01:29:06190 if (!success)
191 task_status_ = ERROR;
192
193 Run();
194}
195
kylechar7a067ec2017-01-07 01:16:28196} // namespace display