blob: 972798901931240bb085f4c8b9267f0f2ec0a38b [file] [log] [blame]
Roman Stratiienko0137f862022-01-04 18:27:40 +02001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "hwc-display-configs"
18
19#include "HwcDisplayConfigs.h"
20
21#include <cmath>
22
23#include "drm/DrmConnector.h"
24#include "utils/log.h"
25
Roman Stratiienkof0c507f2022-01-17 18:29:24 +020026constexpr uint32_t kHeadlessModeDisplayWidthMm = 163;
27constexpr uint32_t kHeadlessModeDisplayHeightMm = 122;
28constexpr uint32_t kHeadlessModeDisplayWidthPx = 1024;
29constexpr uint32_t kHeadlessModeDisplayHeightPx = 768;
30constexpr uint32_t kHeadlessModeDisplayVRefresh = 60;
31
Roman Stratiienko0137f862022-01-04 18:27:40 +020032namespace android {
33
Roman Stratiienko3dacd472022-01-11 19:18:34 +020034// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Roman Stratiienkod0c035b2022-01-21 15:12:56 +020035uint32_t HwcDisplayConfigs::last_config_id = 1;
Roman Stratiienko3dacd472022-01-11 19:18:34 +020036
37void HwcDisplayConfigs::FillHeadless() {
Roman Stratiienkof0c507f2022-01-17 18:29:24 +020038 hwc_configs.clear();
39
40 last_config_id++;
41 preferred_config_id = active_config_id = last_config_id;
42 auto headless_drm_mode_info = (drmModeModeInfo){
43 .hdisplay = kHeadlessModeDisplayWidthPx,
44 .vdisplay = kHeadlessModeDisplayHeightPx,
45 .vrefresh = kHeadlessModeDisplayVRefresh,
46 .name = "HEADLESS-MODE",
47 };
48 hwc_configs[active_config_id] = (HwcDisplayConfig){
49 .id = active_config_id,
50 .group_id = 1,
51 .mode = DrmMode(&headless_drm_mode_info),
52 };
53
54 mm_width = kHeadlessModeDisplayWidthMm;
55 mm_height = kHeadlessModeDisplayHeightMm;
Roman Stratiienko3dacd472022-01-11 19:18:34 +020056}
Roman Stratiienkof0c507f2022-01-17 18:29:24 +020057
Roman Stratiienko3dacd472022-01-11 19:18:34 +020058// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
59HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
60 /* In case UpdateModes will fail we will still have one mode for headless
61 * mode*/
62 FillHeadless();
Roman Stratiienkof0c507f2022-01-17 18:29:24 +020063 /* Read real configs */
Roman Stratiienkoa7913de2022-10-20 13:18:57 +030064 auto ret = connector.UpdateModes();
Roman Stratiienko0137f862022-01-04 18:27:40 +020065 if (ret != 0) {
66 ALOGE("Failed to update display modes %d", ret);
67 return HWC2::Error::BadDisplay;
68 }
69
Roman Stratiienko650299a2022-01-30 23:46:10 +020070 if (connector.GetModes().empty()) {
Roman Stratiienko0137f862022-01-04 18:27:40 +020071 ALOGE("No modes reported by KMS");
72 return HWC2::Error::BadDisplay;
73 }
74
Roman Stratiienkoaa8ec522022-01-17 13:17:56 +020075 hwc_configs.clear();
Roman Stratiienko650299a2022-01-30 23:46:10 +020076 mm_width = connector.GetMmWidth();
77 mm_height = connector.GetMmHeight();
Roman Stratiienkof0c507f2022-01-17 18:29:24 +020078
Roman Stratiienkoaa8ec522022-01-17 13:17:56 +020079 preferred_config_id = 0;
Roman Stratiienkod0c035b2022-01-21 15:12:56 +020080 uint32_t preferred_config_group_id = 0;
Roman Stratiienkoaa8ec522022-01-17 13:17:56 +020081
Roman Stratiienkoa7913de2022-10-20 13:18:57 +030082 auto first_config_id = last_config_id;
Roman Stratiienkod0c035b2022-01-21 15:12:56 +020083 uint32_t last_group_id = 1;
Roman Stratiienko0137f862022-01-04 18:27:40 +020084
85 /* Group modes */
Roman Stratiienko650299a2022-01-30 23:46:10 +020086 for (const auto &mode : connector.GetModes()) {
Roman Stratiienko0137f862022-01-04 18:27:40 +020087 /* Find group for the new mode or create new group */
Roman Stratiienkod0c035b2022-01-21 15:12:56 +020088 uint32_t group_found = 0;
Roman Stratiienko0137f862022-01-04 18:27:40 +020089 for (auto &hwc_config : hwc_configs) {
Roman Stratiienkodf3120f2022-12-07 23:10:55 +020090 if (mode.GetRawMode().hdisplay ==
91 hwc_config.second.mode.GetRawMode().hdisplay &&
92 mode.GetRawMode().vdisplay ==
93 hwc_config.second.mode.GetRawMode().vdisplay) {
Roman Stratiienko0137f862022-01-04 18:27:40 +020094 group_found = hwc_config.second.group_id;
95 }
96 }
97 if (group_found == 0) {
98 group_found = last_group_id++;
99 }
100
101 bool disabled = false;
Roman Stratiienkodf3120f2022-12-07 23:10:55 +0200102 if ((mode.GetRawMode().flags & DRM_MODE_FLAG_3D_MASK) != 0) {
Roman Stratiienko0137f862022-01-04 18:27:40 +0200103 ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)",
Roman Stratiienkodf3120f2022-12-07 23:10:55 +0200104 mode.GetName().c_str());
Roman Stratiienko0137f862022-01-04 18:27:40 +0200105 disabled = true;
106 }
107
108 /* Add config */
109 hwc_configs[last_config_id] = {
110 .id = last_config_id,
111 .group_id = group_found,
112 .mode = mode,
113 .disabled = disabled,
114 };
115
116 /* Chwck if the mode is preferred */
Roman Stratiienkodf3120f2022-12-07 23:10:55 +0200117 if ((mode.GetRawMode().type & DRM_MODE_TYPE_PREFERRED) != 0 &&
Roman Stratiienko0137f862022-01-04 18:27:40 +0200118 preferred_config_id == 0) {
119 preferred_config_id = last_config_id;
120 preferred_config_group_id = group_found;
121 }
122
123 last_config_id++;
124 }
125
126 /* We must have preferred mode. Set first mode as preferred
127 * in case KMS haven't reported anything. */
128 if (preferred_config_id == 0) {
Roman Stratiienkoaa8ec522022-01-17 13:17:56 +0200129 preferred_config_id = first_config_id;
Roman Stratiienko0137f862022-01-04 18:27:40 +0200130 preferred_config_group_id = 1;
131 }
132
Roman Stratiienkod0c035b2022-01-21 15:12:56 +0200133 for (uint32_t group = 1; group < last_group_id; group++) {
Roman Stratiienko0137f862022-01-04 18:27:40 +0200134 bool has_interlaced = false;
135 bool has_progressive = false;
136 for (auto &hwc_config : hwc_configs) {
137 if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
138 continue;
139 }
140
141 if (hwc_config.second.IsInterlaced()) {
142 has_interlaced = true;
143 } else {
144 has_progressive = true;
145 }
146 }
147
Roman Stratiienkoa7913de2022-10-20 13:18:57 +0300148 auto has_both = has_interlaced && has_progressive;
Roman Stratiienko0137f862022-01-04 18:27:40 +0200149 if (!has_both) {
150 continue;
151 }
152
153 bool group_contains_preferred_interlaced = false;
154 if (group == preferred_config_group_id &&
155 hwc_configs[preferred_config_id].IsInterlaced()) {
156 group_contains_preferred_interlaced = true;
157 }
158
159 for (auto &hwc_config : hwc_configs) {
160 if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
161 continue;
162 }
163
Roman Stratiienkoa7913de2022-10-20 13:18:57 +0300164 auto disable = group_contains_preferred_interlaced
Roman Stratiienko0137f862022-01-04 18:27:40 +0200165 ? !hwc_config.second.IsInterlaced()
166 : hwc_config.second.IsInterlaced();
167
168 if (disable) {
169 ALOGI(
170 "Group %i: Disabling display mode %s (This group should consist "
171 "of %s modes)",
Roman Stratiienkodf3120f2022-12-07 23:10:55 +0200172 group, hwc_config.second.mode.GetName().c_str(),
Roman Stratiienko0137f862022-01-04 18:27:40 +0200173 group_contains_preferred_interlaced ? "interlaced" : "progressive");
174
175 hwc_config.second.disabled = true;
176 }
177 }
178 }
179
180 /* Group should not contain 2 modes with FPS delta less than ~1HZ
181 * otherwise android.graphics.cts.SetFrameRateTest CTS will fail
182 */
183 constexpr float kMinFpsDelta = 1.0; // FPS
Roman Stratiienkod0c035b2022-01-21 15:12:56 +0200184 for (uint32_t m1 = first_config_id; m1 < last_config_id; m1++) {
185 for (uint32_t m2 = first_config_id; m2 < last_config_id; m2++) {
Roman Stratiienko0137f862022-01-04 18:27:40 +0200186 if (m1 != m2 && hwc_configs[m1].group_id == hwc_configs[m2].group_id &&
187 !hwc_configs[m1].disabled && !hwc_configs[m2].disabled &&
Roman Stratiienkodf3120f2022-12-07 23:10:55 +0200188 fabsf(hwc_configs[m1].mode.GetVRefresh() -
189 hwc_configs[m2].mode.GetVRefresh()) < kMinFpsDelta) {
Roman Stratiienko0137f862022-01-04 18:27:40 +0200190 ALOGI(
191 "Group %i: Disabling display mode %s (Refresh rate value is "
192 "too close to existing mode %s)",
Roman Stratiienkodf3120f2022-12-07 23:10:55 +0200193 hwc_configs[m2].group_id, hwc_configs[m2].mode.GetName().c_str(),
194 hwc_configs[m1].mode.GetName().c_str());
Roman Stratiienko0137f862022-01-04 18:27:40 +0200195
196 hwc_configs[m2].disabled = true;
197 }
198 }
199 }
200
Roman Stratiienko0137f862022-01-04 18:27:40 +0200201 return HWC2::Error::None;
202}
203
204} // namespace android