• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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 #include "DisplayFinder.h"
18 
19 #include <android-base/parseint.h>
20 #include <android-base/properties.h>
21 #include <android-base/strings.h>
22 #include <device_config_shared.h>
23 
24 #include "Common.h"
25 #include "HostUtils.h"
26 
27 namespace aidl::android::hardware::graphics::composer3::impl {
28 namespace {
29 
HertzToPeriodNanos(uint32_t hertz)30 constexpr int32_t HertzToPeriodNanos(uint32_t hertz) {
31   return 1000 * 1000 * 1000 / hertz;
32 }
33 
findCuttlefishDisplays(std::vector<DisplayMultiConfigs> * outDisplays)34 HWC3::Error findCuttlefishDisplays(std::vector<DisplayMultiConfigs>* outDisplays) {
35   DEBUG_LOG("%s", __FUNCTION__);
36 
37   // TODO: replace with initializing directly from DRM info.
38   const auto deviceConfig = cuttlefish::GetDeviceConfig();
39 
40   int64_t displayId = 0;
41   for (const auto& deviceDisplayConfig : deviceConfig.display_config()) {
42     const auto vsyncPeriodNanos =
43         HertzToPeriodNanos(deviceDisplayConfig.refresh_rate_hz());
44 
45     DisplayMultiConfigs display = {
46         .displayId = displayId,
47         .activeConfigId = 0,
48         .configs =
49             {
50                 DisplayConfig(0,                             //
51                               deviceDisplayConfig.width(),   //
52                               deviceDisplayConfig.height(),  //
53                               deviceDisplayConfig.dpi(),     //
54                               deviceDisplayConfig.dpi(),     //
55                               vsyncPeriodNanos),
56             },
57     };
58     outDisplays->push_back(display);
59     ++displayId;
60   }
61 
62   return HWC3::Error::None;
63 }
64 
getVsyncHzFromProperty()65 static int getVsyncHzFromProperty() {
66   static constexpr const auto kVsyncProp = "ro.boot.qemu.vsync";
67 
68   const auto vsyncProp = ::android::base::GetProperty(kVsyncProp, "");
69   DEBUG_LOG("%s: prop value is: %s", __FUNCTION__, vsyncProp.c_str());
70 
71   uint64_t vsyncPeriod;
72   if (!::android::base::ParseUint(vsyncProp, &vsyncPeriod)) {
73     ALOGE("%s: failed to parse vsync period '%s', returning default 60",
74           __FUNCTION__, vsyncProp.c_str());
75     return 60;
76   }
77 
78   return static_cast<int>(vsyncPeriod);
79 }
80 
findGoldfishPrimaryDisplay(std::vector<DisplayMultiConfigs> * outDisplays)81 HWC3::Error findGoldfishPrimaryDisplay(
82     std::vector<DisplayMultiConfigs>* outDisplays) {
83   DEBUG_LOG("%s", __FUNCTION__);
84 
85   DEFINE_AND_VALIDATE_HOST_CONNECTION
86   hostCon->lock();
87   const int32_t vsyncPeriodNanos = HertzToPeriodNanos(getVsyncHzFromProperty());
88   DisplayMultiConfigs display;
89   display.displayId = 0;
90   if (rcEnc->hasHWCMultiConfigs()) {
91     int count = rcEnc->rcGetFBDisplayConfigsCount(rcEnc);
92     if (count <= 0) {
93       ALOGE("%s failed to allocate primary display, config count %d", __func__,
94             count);
95       return HWC3::Error::NoResources;
96     }
97     display.activeConfigId = rcEnc->rcGetFBDisplayActiveConfig(rcEnc);
98     for (int configId = 0; configId < count; configId++) {
99       display.configs.push_back(DisplayConfig(
100           configId,                                                       //
101           rcEnc->rcGetFBDisplayConfigsParam(rcEnc, configId, FB_WIDTH),   //
102           rcEnc->rcGetFBDisplayConfigsParam(rcEnc, configId, FB_HEIGHT),  //
103           rcEnc->rcGetFBDisplayConfigsParam(rcEnc, configId, FB_XDPI),    //
104           rcEnc->rcGetFBDisplayConfigsParam(rcEnc, configId, FB_YDPI),    //
105           vsyncPeriodNanos                                                //
106           ));
107     }
108   } else {
109     display.activeConfigId = 0;
110     display.configs.push_back(DisplayConfig(
111         0,                                      //
112         rcEnc->rcGetFBParam(rcEnc, FB_WIDTH),   //
113         rcEnc->rcGetFBParam(rcEnc, FB_HEIGHT),  //
114         rcEnc->rcGetFBParam(rcEnc, FB_XDPI),    //
115         rcEnc->rcGetFBParam(rcEnc, FB_YDPI),    //
116         vsyncPeriodNanos                        //
117         ));
118   }
119   hostCon->unlock();
120 
121   outDisplays->push_back(display);
122 
123   return HWC3::Error::None;
124 }
125 
findGoldfishSecondaryDisplays(std::vector<DisplayMultiConfigs> * outDisplays)126 HWC3::Error findGoldfishSecondaryDisplays(
127     std::vector<DisplayMultiConfigs>* outDisplays) {
128   DEBUG_LOG("%s", __FUNCTION__);
129 
130   static constexpr const char kExternalDisplayProp[] =
131       "hwservicemanager.external.displays";
132 
133   const auto propString =
134       ::android::base::GetProperty(kExternalDisplayProp, "");
135   DEBUG_LOG("%s: prop value is: %s", __FUNCTION__, propString.c_str());
136 
137   if (propString.empty()) {
138     return HWC3::Error::None;
139   }
140 
141   const std::vector<std::string> propStringParts =
142       ::android::base::Split(propString, ",");
143   if (propStringParts.size() % 5 != 0) {
144     ALOGE("%s: Invalid syntax for system prop %s which is %s", __FUNCTION__,
145           kExternalDisplayProp, propString.c_str());
146     return HWC3::Error::BadParameter;
147   }
148 
149   std::vector<int> propIntParts;
150   for (const std::string& propStringPart : propStringParts) {
151     int propIntPart;
152     if (!::android::base::ParseInt(propStringPart, &propIntPart)) {
153       ALOGE("%s: Invalid syntax for system prop %s which is %s", __FUNCTION__,
154             kExternalDisplayProp, propString.c_str());
155       return HWC3::Error::BadParameter;
156     }
157     propIntParts.push_back(propIntPart);
158   }
159 
160   int64_t secondaryDisplayId = 1;
161   while (!propIntParts.empty()) {
162     DisplayMultiConfigs display;
163     display.displayId = secondaryDisplayId;
164     display.activeConfigId = 0;
165     display.configs.push_back(DisplayConfig(
166         0,                                       //
167         /*width=*/propIntParts[1],               //
168         /*heighth=*/propIntParts[2],             //
169         /*dpiXh=*/propIntParts[3],               //
170         /*dpiYh=*/propIntParts[3],               //
171         /*vsyncPeriod=*/HertzToPeriodNanos(160)  //
172         ));
173     outDisplays->push_back(display);
174 
175     ++secondaryDisplayId;
176 
177     propIntParts.erase(propIntParts.begin(), propIntParts.begin() + 5);
178   }
179 
180   return HWC3::Error::None;
181 }
182 
findGoldfishDisplays(std::vector<DisplayMultiConfigs> * outDisplays)183 HWC3::Error findGoldfishDisplays(std::vector<DisplayMultiConfigs>* outDisplays) {
184   HWC3::Error error = findGoldfishPrimaryDisplay(outDisplays);
185   if (error != HWC3::Error::None) {
186     ALOGE("%s failed to find Goldfish primary display", __FUNCTION__);
187     return error;
188   }
189 
190   error = findGoldfishSecondaryDisplays(outDisplays);
191   if (error != HWC3::Error::None) {
192     ALOGE("%s failed to find Goldfish secondary displays", __FUNCTION__);
193   }
194 
195   return error;
196 }
197 
198 // This is currently only used for Gem5 bring-up where virtio-gpu and drm
199 // are not currently available. For now, just return a placeholder display.
findNoOpDisplays(std::vector<DisplayMultiConfigs> * outDisplays)200 HWC3::Error findNoOpDisplays(std::vector<DisplayMultiConfigs>* outDisplays) {
201   outDisplays->push_back(DisplayMultiConfigs{
202       .displayId = 0,
203       .activeConfigId = 0,
204       .configs = {DisplayConfig(0,
205                                 /*width=*/720,                          //
206                                 /*heighth=*/1280,                       //
207                                 /*dpiXh=*/320,                          //
208                                 /*dpiYh=*/320,                          //
209                                 /*vsyncPeriod=*/HertzToPeriodNanos(30)  //
210                                 )},
211   });
212 
213   return HWC3::Error::None;
214 }
215 
findDrmDisplays(const DrmPresenter & drm,std::vector<DisplayMultiConfigs> * outDisplays)216 HWC3::Error findDrmDisplays(const DrmPresenter& drm,
217                             std::vector<DisplayMultiConfigs>* outDisplays) {
218   outDisplays->clear();
219 
220   std::vector<DrmPresenter::DisplayConfig> drmDisplayConfigs;
221 
222   HWC3::Error error = drm.getDisplayConfigs(&drmDisplayConfigs);
223   if (error != HWC3::Error::None) {
224     ALOGE("%s failed to find displays from DRM.", __FUNCTION__);
225     return error;
226   }
227 
228   for (const DrmPresenter::DisplayConfig drmDisplayConfig : drmDisplayConfigs) {
229     outDisplays->push_back(DisplayMultiConfigs{
230       .displayId = drmDisplayConfig.id,
231       .activeConfigId = static_cast<int32_t>(drmDisplayConfig.id),
232       .configs = {
233         DisplayConfig(static_cast<int32_t>(drmDisplayConfig.id),
234                       drmDisplayConfig.width,
235                       drmDisplayConfig.height,
236                       drmDisplayConfig.dpiX,
237                       drmDisplayConfig.dpiY,
238                       HertzToPeriodNanos(drmDisplayConfig.refreshRateHz)),
239       },
240     });
241   }
242 
243   return HWC3::Error::None;
244 }
245 
246 }  // namespace
247 
findDisplays(const DrmPresenter * drm,std::vector<DisplayMultiConfigs> * outDisplays)248 HWC3::Error findDisplays(const DrmPresenter* drm,
249                          std::vector<DisplayMultiConfigs>* outDisplays) {
250   HWC3::Error error = HWC3::Error::None;
251   if (IsInNoOpCompositionMode()) {
252     error = findNoOpDisplays(outDisplays);
253   } else if (IsInDrmDisplayFinderMode()) {
254     if (drm == nullptr) {
255       ALOGE("%s asked to find displays from DRM, but DRM not available.",
256             __FUNCTION__);
257       return HWC3::Error::NoResources;
258     }
259     error = findDrmDisplays(*drm, outDisplays);
260   } else if (IsCuttlefish()) {
261     error = findCuttlefishDisplays(outDisplays);
262   } else {
263     error = findGoldfishDisplays(outDisplays);
264   }
265 
266   if (error != HWC3::Error::None) {
267     ALOGE("%s failed to find displays", __FUNCTION__);
268     return error;
269   }
270 
271   for (auto& display : *outDisplays) {
272     DisplayConfig::addConfigGroups(&display.configs);
273   }
274 
275   return HWC3::Error::None;
276 }
277 
278 }  // namespace aidl::android::hardware::graphics::composer3::impl
279