blob: e3d17a2d837bb58454cc8d78bb294adba7b2e2d5 [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
26namespace android {
27
28// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
29HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
30 int ret = connector.UpdateModes();
31 if (ret != 0) {
32 ALOGE("Failed to update display modes %d", ret);
33 return HWC2::Error::BadDisplay;
34 }
35
Roman Stratiienko0137f862022-01-04 18:27:40 +020036 if (connector.modes().empty()) {
37 ALOGE("No modes reported by KMS");
38 return HWC2::Error::BadDisplay;
39 }
40
Roman Stratiienkoaa8ec522022-01-17 13:17:56 +020041 hwc_configs.clear();
42 preferred_config_id = 0;
43 int preferred_config_group_id = 0;
44
45 int first_config_id = last_config_id;
Roman Stratiienko0137f862022-01-04 18:27:40 +020046 int last_group_id = 1;
47
48 /* Group modes */
49 for (const auto &mode : connector.modes()) {
50 /* Find group for the new mode or create new group */
51 int group_found = 0;
52 for (auto &hwc_config : hwc_configs) {
53 if (mode.h_display() == hwc_config.second.mode.h_display() &&
54 mode.v_display() == hwc_config.second.mode.v_display()) {
55 group_found = hwc_config.second.group_id;
56 }
57 }
58 if (group_found == 0) {
59 group_found = last_group_id++;
60 }
61
62 bool disabled = false;
63 if ((mode.flags() & DRM_MODE_FLAG_3D_MASK) != 0) {
64 ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)",
65 mode.name().c_str());
66 disabled = true;
67 }
68
69 /* Add config */
70 hwc_configs[last_config_id] = {
71 .id = last_config_id,
72 .group_id = group_found,
73 .mode = mode,
74 .disabled = disabled,
75 };
76
77 /* Chwck if the mode is preferred */
78 if ((mode.type() & DRM_MODE_TYPE_PREFERRED) != 0 &&
79 preferred_config_id == 0) {
80 preferred_config_id = last_config_id;
81 preferred_config_group_id = group_found;
82 }
83
84 last_config_id++;
85 }
86
87 /* We must have preferred mode. Set first mode as preferred
88 * in case KMS haven't reported anything. */
89 if (preferred_config_id == 0) {
Roman Stratiienkoaa8ec522022-01-17 13:17:56 +020090 preferred_config_id = first_config_id;
Roman Stratiienko0137f862022-01-04 18:27:40 +020091 preferred_config_group_id = 1;
92 }
93
94 for (int group = 1; group < last_group_id; group++) {
95 bool has_interlaced = false;
96 bool has_progressive = false;
97 for (auto &hwc_config : hwc_configs) {
98 if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
99 continue;
100 }
101
102 if (hwc_config.second.IsInterlaced()) {
103 has_interlaced = true;
104 } else {
105 has_progressive = true;
106 }
107 }
108
109 bool has_both = has_interlaced && has_progressive;
110 if (!has_both) {
111 continue;
112 }
113
114 bool group_contains_preferred_interlaced = false;
115 if (group == preferred_config_group_id &&
116 hwc_configs[preferred_config_id].IsInterlaced()) {
117 group_contains_preferred_interlaced = true;
118 }
119
120 for (auto &hwc_config : hwc_configs) {
121 if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
122 continue;
123 }
124
125 bool disable = group_contains_preferred_interlaced
126 ? !hwc_config.second.IsInterlaced()
127 : hwc_config.second.IsInterlaced();
128
129 if (disable) {
130 ALOGI(
131 "Group %i: Disabling display mode %s (This group should consist "
132 "of %s modes)",
133 group, hwc_config.second.mode.name().c_str(),
134 group_contains_preferred_interlaced ? "interlaced" : "progressive");
135
136 hwc_config.second.disabled = true;
137 }
138 }
139 }
140
141 /* Group should not contain 2 modes with FPS delta less than ~1HZ
142 * otherwise android.graphics.cts.SetFrameRateTest CTS will fail
143 */
144 constexpr float kMinFpsDelta = 1.0; // FPS
Roman Stratiienkoaa8ec522022-01-17 13:17:56 +0200145 for (int m1 = first_config_id; m1 < last_config_id; m1++) {
146 for (int m2 = first_config_id; m2 < last_config_id; m2++) {
Roman Stratiienko0137f862022-01-04 18:27:40 +0200147 if (m1 != m2 && hwc_configs[m1].group_id == hwc_configs[m2].group_id &&
148 !hwc_configs[m1].disabled && !hwc_configs[m2].disabled &&
149 fabsf(hwc_configs[m1].mode.v_refresh() -
150 hwc_configs[m2].mode.v_refresh()) < kMinFpsDelta) {
151 ALOGI(
152 "Group %i: Disabling display mode %s (Refresh rate value is "
153 "too close to existing mode %s)",
154 hwc_configs[m2].group_id, hwc_configs[m2].mode.name().c_str(),
155 hwc_configs[m1].mode.name().c_str());
156
157 hwc_configs[m2].disabled = true;
158 }
159 }
160 }
161
162 return HWC2::Error::None;
163}
164
165} // namespace android