OSDN Git Service

f6ccdb79eb2d4b1baa32da590352a080432e947d
[android-x86/external-drm_hwcomposer.git] / hwc2_device / HwcDisplayConfigs.cpp
1 /*
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
26 constexpr uint32_t kHeadlessModeDisplayWidthMm = 163;
27 constexpr uint32_t kHeadlessModeDisplayHeightMm = 122;
28 constexpr uint32_t kHeadlessModeDisplayWidthPx = 1024;
29 constexpr uint32_t kHeadlessModeDisplayHeightPx = 768;
30 constexpr uint32_t kHeadlessModeDisplayVRefresh = 60;
31
32 namespace android {
33
34 // NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
35 HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
36   /* In case UpdateModes will fail we will still have one mode for headless
37    * mode*/
38   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;
56
57   /* Read real configs */
58   int ret = connector.UpdateModes();
59   if (ret != 0) {
60     ALOGE("Failed to update display modes %d", ret);
61     return HWC2::Error::BadDisplay;
62   }
63
64   if (connector.GetModes().empty()) {
65     ALOGE("No modes reported by KMS");
66     return HWC2::Error::BadDisplay;
67   }
68
69   hwc_configs.clear();
70   mm_width = connector.GetMmWidth();
71   mm_height = connector.GetMmHeight();
72
73   preferred_config_id = 0;
74   int preferred_config_group_id = 0;
75
76   int first_config_id = last_config_id;
77   int last_group_id = 1;
78
79   /* Group modes */
80   for (const auto &mode : connector.GetModes()) {
81     /* Find group for the new mode or create new group */
82     int group_found = 0;
83     for (auto &hwc_config : hwc_configs) {
84       if (mode.h_display() == hwc_config.second.mode.h_display() &&
85           mode.v_display() == hwc_config.second.mode.v_display()) {
86         group_found = hwc_config.second.group_id;
87       }
88     }
89     if (group_found == 0) {
90       group_found = last_group_id++;
91     }
92
93     bool disabled = false;
94     if ((mode.flags() & DRM_MODE_FLAG_3D_MASK) != 0) {
95       ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)",
96             mode.name().c_str());
97       disabled = true;
98     }
99
100     /* Add config */
101     hwc_configs[last_config_id] = {
102         .id = last_config_id,
103         .group_id = group_found,
104         .mode = mode,
105         .disabled = disabled,
106     };
107
108     /* Chwck if the mode is preferred */
109     if ((mode.type() & DRM_MODE_TYPE_PREFERRED) != 0 &&
110         preferred_config_id == 0) {
111       preferred_config_id = last_config_id;
112       preferred_config_group_id = group_found;
113     }
114
115     last_config_id++;
116   }
117
118   /* We must have preferred mode. Set first mode as preferred
119    * in case KMS haven't reported anything. */
120   if (preferred_config_id == 0) {
121     preferred_config_id = first_config_id;
122     preferred_config_group_id = 1;
123   }
124
125   for (int group = 1; group < last_group_id; group++) {
126     bool has_interlaced = false;
127     bool has_progressive = false;
128     for (auto &hwc_config : hwc_configs) {
129       if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
130         continue;
131       }
132
133       if (hwc_config.second.IsInterlaced()) {
134         has_interlaced = true;
135       } else {
136         has_progressive = true;
137       }
138     }
139
140     bool has_both = has_interlaced && has_progressive;
141     if (!has_both) {
142       continue;
143     }
144
145     bool group_contains_preferred_interlaced = false;
146     if (group == preferred_config_group_id &&
147         hwc_configs[preferred_config_id].IsInterlaced()) {
148       group_contains_preferred_interlaced = true;
149     }
150
151     for (auto &hwc_config : hwc_configs) {
152       if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
153         continue;
154       }
155
156       bool disable = group_contains_preferred_interlaced
157                          ? !hwc_config.second.IsInterlaced()
158                          : hwc_config.second.IsInterlaced();
159
160       if (disable) {
161         ALOGI(
162             "Group %i: Disabling display mode %s (This group should consist "
163             "of %s modes)",
164             group, hwc_config.second.mode.name().c_str(),
165             group_contains_preferred_interlaced ? "interlaced" : "progressive");
166
167         hwc_config.second.disabled = true;
168       }
169     }
170   }
171
172   /* Group should not contain 2 modes with FPS delta less than ~1HZ
173    * otherwise android.graphics.cts.SetFrameRateTest CTS will fail
174    */
175   constexpr float kMinFpsDelta = 1.0;  // FPS
176   for (int m1 = first_config_id; m1 < last_config_id; m1++) {
177     for (int m2 = first_config_id; m2 < last_config_id; m2++) {
178       if (m1 != m2 && hwc_configs[m1].group_id == hwc_configs[m2].group_id &&
179           !hwc_configs[m1].disabled && !hwc_configs[m2].disabled &&
180           fabsf(hwc_configs[m1].mode.v_refresh() -
181                 hwc_configs[m2].mode.v_refresh()) < kMinFpsDelta) {
182         ALOGI(
183             "Group %i: Disabling display mode %s (Refresh rate value is "
184             "too close to existing mode %s)",
185             hwc_configs[m2].group_id, hwc_configs[m2].mode.name().c_str(),
186             hwc_configs[m1].mode.name().c_str());
187
188         hwc_configs[m2].disabled = true;
189       }
190     }
191   }
192
193   /* Set active mode to be valid mode */
194   active_config_id = preferred_config_id;
195   return HWC2::Error::None;
196 }
197
198 }  // namespace android