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:38