1 /*
2 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *    * Redistributions of source code must retain the above copyright
8 *      notice, this list of conditions and the following disclaimer.
9 *    * Redistributions in binary form must reproduce the above
10 *      copyright notice, this list of conditions and the following
11 *      disclaimer in the documentation and/or other materials provided
12 *      with the distribution.
13 *    * Neither the name of The Linux Foundation. nor the names of its
14 *      contributors may be used to endorse or promote products derived
15 *      from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 
30 #include <core/buffer_allocator.h>
31 #include <utils/debug.h>
32 #include <sync/sync.h>
33 #include <profiler.h>
34 
35 #include "hwc_buffer_sync_handler.h"
36 #include "hwc_session.h"
37 
38 #define __CLASS__ "HWCSession"
39 
40 namespace sdm {
41 
42 using ::android::hardware::Void;
43 
StartServices()44 void HWCSession::StartServices() {
45   status_t status = IDisplayConfig::registerAsService();
46   if (status != OK) {
47     DLOGW("Could not register IDisplayConfig as service (%d).", status);
48   } else {
49     DLOGI("IDisplayConfig service registration completed.");
50   }
51 }
52 
MapDisplayType(IDisplayConfig::DisplayType dpy)53 int MapDisplayType(IDisplayConfig::DisplayType dpy) {
54   switch (dpy) {
55     case IDisplayConfig::DisplayType::DISPLAY_PRIMARY:
56       return HWC_DISPLAY_PRIMARY;
57 
58     case IDisplayConfig::DisplayType::DISPLAY_EXTERNAL:
59       return HWC_DISPLAY_EXTERNAL;
60 
61     case IDisplayConfig::DisplayType::DISPLAY_VIRTUAL:
62       return HWC_DISPLAY_VIRTUAL;
63 
64     default:
65       break;
66   }
67 
68   return -EINVAL;
69 }
70 
MapExternalStatus(IDisplayConfig::DisplayExternalStatus status)71 HWCDisplay::DisplayStatus MapExternalStatus(IDisplayConfig::DisplayExternalStatus status) {
72   switch (status) {
73     case IDisplayConfig::DisplayExternalStatus::EXTERNAL_OFFLINE:
74       return HWCDisplay::kDisplayStatusOffline;
75 
76     case IDisplayConfig::DisplayExternalStatus::EXTERNAL_ONLINE:
77       return HWCDisplay::kDisplayStatusOnline;
78 
79     case IDisplayConfig::DisplayExternalStatus::EXTERNAL_PAUSE:
80       return HWCDisplay::kDisplayStatusPause;
81 
82     case IDisplayConfig::DisplayExternalStatus::EXTERNAL_RESUME:
83       return HWCDisplay::kDisplayStatusResume;
84 
85     default:
86       break;
87   }
88 
89   return HWCDisplay::kDisplayStatusInvalid;
90 }
91 
92 // Methods from ::vendor::hardware::display::config::V1_0::IDisplayConfig follow.
isDisplayConnected(IDisplayConfig::DisplayType dpy,isDisplayConnected_cb _hidl_cb)93 Return<void> HWCSession::isDisplayConnected(IDisplayConfig::DisplayType dpy,
94                                             isDisplayConnected_cb _hidl_cb) {
95   SCOPE_LOCK(locker_);
96 
97   int32_t error = -EINVAL;
98   bool connected = false;
99 
100   int disp_id = MapDisplayType(dpy);
101   if (disp_id >= 0) {
102     connected = hwc_display_[disp_id];
103     error = 0;
104   }
105 
106   _hidl_cb(error, connected);
107 
108   return Void();
109 }
110 
SetSecondaryDisplayStatus(int disp_id,HWCDisplay::DisplayStatus status)111 int32_t HWCSession::SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status) {
112   SCOPE_LOCK(locker_);
113 
114   if (disp_id < 0) {
115     return -EINVAL;
116   }
117 
118   DLOGI("Display = %d, Status = %d", disp_id, status);
119 
120   if (disp_id == HWC_DISPLAY_PRIMARY) {
121     DLOGE("Not supported for this display");
122   } else if (!hwc_display_[disp_id]) {
123     DLOGW("Display is not connected");
124   } else {
125     return hwc_display_[disp_id]->SetDisplayStatus(status);
126   }
127 
128   return -EINVAL;
129 }
130 
setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy,IDisplayConfig::DisplayExternalStatus status)131 Return<int32_t> HWCSession::setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy,
132                                                   IDisplayConfig::DisplayExternalStatus status) {
133   return SetSecondaryDisplayStatus(MapDisplayType(dpy), MapExternalStatus(status));
134 }
135 
configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op,uint32_t refreshRate)136 Return<int32_t> HWCSession::configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op,
137                                                    uint32_t refreshRate) {
138   SCOPE_LOCK(locker_);
139 
140   HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
141 
142   switch (op) {
143     case IDisplayConfig::DisplayDynRefreshRateOp::DISABLE_METADATA_DYN_REFRESH_RATE:
144       return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
145 
146     case IDisplayConfig::DisplayDynRefreshRateOp::ENABLE_METADATA_DYN_REFRESH_RATE:
147       return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true);
148 
149     case IDisplayConfig::DisplayDynRefreshRateOp::SET_BINDER_DYN_REFRESH_RATE:
150       return hwc_display->Perform(HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE, refreshRate);
151 
152     default:
153       DLOGW("Invalid operation %d", op);
154       return -EINVAL;
155   }
156 
157   return 0;
158 }
159 
GetConfigCount(int disp_id,uint32_t * count)160 int32_t HWCSession::GetConfigCount(int disp_id, uint32_t *count) {
161   SCOPE_LOCK(locker_);
162 
163   if (disp_id >= 0 && hwc_display_[disp_id]) {
164     return hwc_display_[disp_id]->GetDisplayConfigCount(count);
165   }
166 
167   return -EINVAL;
168 }
169 
getConfigCount(IDisplayConfig::DisplayType dpy,getConfigCount_cb _hidl_cb)170 Return<void> HWCSession::getConfigCount(IDisplayConfig::DisplayType dpy,
171                                         getConfigCount_cb _hidl_cb) {
172   uint32_t count = 0;
173   int32_t error = GetConfigCount(MapDisplayType(dpy), &count);
174 
175   _hidl_cb(error, count);
176 
177   return Void();
178 }
179 
GetActiveConfigIndex(int disp_id,uint32_t * config)180 int32_t HWCSession::GetActiveConfigIndex(int disp_id, uint32_t *config) {
181   SCOPE_LOCK(locker_);
182 
183   if (disp_id >= 0 && hwc_display_[disp_id]) {
184     return hwc_display_[disp_id]->GetActiveDisplayConfig(config);
185   }
186 
187   return -EINVAL;
188 }
189 
getActiveConfig(IDisplayConfig::DisplayType dpy,getActiveConfig_cb _hidl_cb)190 Return<void> HWCSession::getActiveConfig(IDisplayConfig::DisplayType dpy,
191                                          getActiveConfig_cb _hidl_cb) {
192   uint32_t config = 0;
193   int32_t error = GetActiveConfigIndex(MapDisplayType(dpy), &config);
194 
195   _hidl_cb(error, config);
196 
197   return Void();
198 }
199 
SetActiveConfigIndex(int disp_id,uint32_t config)200 int32_t HWCSession::SetActiveConfigIndex(int disp_id, uint32_t config) {
201   SCOPE_LOCK(locker_);
202 
203   if (disp_id < 0) {
204     return -EINVAL;
205   }
206 
207   int32_t error = -EINVAL;
208   if (hwc_display_[disp_id]) {
209     error = hwc_display_[disp_id]->SetActiveDisplayConfig(config);
210     if (!error) {
211       Refresh(0);
212     }
213   }
214 
215   return error;
216 }
217 
setActiveConfig(IDisplayConfig::DisplayType dpy,uint32_t config)218 Return<int32_t> HWCSession::setActiveConfig(IDisplayConfig::DisplayType dpy, uint32_t config) {
219   return SetActiveConfigIndex(MapDisplayType(dpy), config);
220 }
221 
getDisplayAttributes(uint32_t configIndex,IDisplayConfig::DisplayType dpy,getDisplayAttributes_cb _hidl_cb)222 Return<void> HWCSession::getDisplayAttributes(uint32_t configIndex,
223                                               IDisplayConfig::DisplayType dpy,
224                                               getDisplayAttributes_cb _hidl_cb) {
225   SCOPE_LOCK(locker_);
226 
227   int32_t error = -EINVAL;
228   IDisplayConfig::DisplayAttributes display_attributes = {};
229 
230   int disp_id = MapDisplayType(dpy);
231   if (disp_id >= 0 && hwc_display_[disp_id]) {
232     DisplayConfigVariableInfo hwc_display_attributes;
233     error = hwc_display_[disp_id]->GetDisplayAttributesForConfig(static_cast<int>(configIndex),
234                                                                  &hwc_display_attributes);
235     if (!error) {
236       display_attributes.vsyncPeriod = hwc_display_attributes.vsync_period_ns;
237       display_attributes.xRes = hwc_display_attributes.x_pixels;
238       display_attributes.yRes = hwc_display_attributes.y_pixels;
239       display_attributes.xDpi = hwc_display_attributes.x_dpi;
240       display_attributes.yDpi = hwc_display_attributes.y_dpi;
241       display_attributes.panelType = IDisplayConfig::DisplayPortType::DISPLAY_PORT_DEFAULT;
242       display_attributes.isYuv = hwc_display_attributes.is_yuv;
243     }
244   }
245 
246   return Void();
247 }
248 
setPanelBrightness(uint32_t level)249 Return<int32_t> HWCSession::setPanelBrightness(uint32_t level) {
250   SCOPE_LOCK(locker_);
251 
252   int32_t error = -EINVAL;
253   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
254     error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(static_cast<int>(level));
255     if (error) {
256       DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error);
257     }
258   }
259 
260   return error;
261 }
262 
GetPanelBrightness(int * level)263 int32_t HWCSession::GetPanelBrightness(int *level) {
264   SCOPE_LOCK(locker_);
265 
266   int32_t error = -EINVAL;
267 
268   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
269     error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(level);
270     if (error) {
271       DLOGE("Failed to get the panel brightness. Error = %d", error);
272     }
273   }
274 
275   return error;
276 }
277 
getPanelBrightness(getPanelBrightness_cb _hidl_cb)278 Return<void> HWCSession::getPanelBrightness(getPanelBrightness_cb _hidl_cb) {
279   int level = 0;
280   int32_t error = GetPanelBrightness(&level);
281 
282   _hidl_cb(error, static_cast<uint32_t>(level));
283 
284   return Void();
285 }
286 
MinHdcpEncryptionLevelChanged(int disp_id,uint32_t min_enc_level)287 int32_t HWCSession::MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level) {
288   SCOPE_LOCK(locker_);
289 
290   DLOGI("Display %d", disp_id);
291 
292   if (disp_id < 0) {
293     return -EINVAL;
294   }
295 
296   if (disp_id != HWC_DISPLAY_EXTERNAL) {
297     DLOGE("Not supported for display");
298   } else if (!hwc_display_[disp_id]) {
299     DLOGW("Display is not connected");
300   } else {
301     return hwc_display_[disp_id]->OnMinHdcpEncryptionLevelChange(min_enc_level);
302   }
303 
304   return -EINVAL;
305 }
306 
minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,uint32_t min_enc_level)307 Return<int32_t> HWCSession::minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,
308                                                           uint32_t min_enc_level) {
309   return MinHdcpEncryptionLevelChanged(MapDisplayType(dpy), min_enc_level);
310 }
311 
refreshScreen()312 Return<int32_t> HWCSession::refreshScreen() {
313   SCOPE_LOCK(locker_);
314 
315   Refresh(HWC_DISPLAY_PRIMARY);
316 
317   return 0;
318 }
319 
ControlPartialUpdate(int disp_id,bool enable)320 int32_t HWCSession::ControlPartialUpdate(int disp_id, bool enable) {
321   SCOPE_LOCK(locker_);
322 
323   if (disp_id < 0) {
324     return -EINVAL;
325   }
326 
327   if (disp_id != HWC_DISPLAY_PRIMARY) {
328     DLOGW("CONTROL_PARTIAL_UPDATE is not applicable for display = %d", disp_id);
329     return -EINVAL;
330   }
331 
332   HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
333   if (!hwc_display) {
334     DLOGE("primary display object is not instantiated");
335     return -EINVAL;
336   }
337 
338   uint32_t pending = 0;
339   DisplayError hwc_error = hwc_display->ControlPartialUpdate(enable, &pending);
340 
341   if (hwc_error == kErrorNone) {
342     if (!pending) {
343       return 0;
344     }
345   } else if (hwc_error == kErrorNotSupported) {
346     return 0;
347   } else {
348     return -EINVAL;
349   }
350 
351   // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future.
352   Refresh(HWC_DISPLAY_PRIMARY);
353 
354   // Wait until partial update control is complete
355   int32_t error = locker_.WaitFinite(kPartialUpdateControlTimeoutMs);
356 
357   return error;
358 }
359 
controlPartialUpdate(IDisplayConfig::DisplayType dpy,bool enable)360 Return<int32_t> HWCSession::controlPartialUpdate(IDisplayConfig::DisplayType dpy, bool enable) {
361   return ControlPartialUpdate(MapDisplayType(dpy), enable);
362 }
363 
toggleScreenUpdate(bool on)364 Return<int32_t> HWCSession::toggleScreenUpdate(bool on) {
365   SCOPE_LOCK(locker_);
366 
367   int32_t error = -EINVAL;
368   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
369     error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(on);
370     if (error) {
371       DLOGE("Failed to toggle screen updates = %d. Error = %d", on, error);
372     }
373   }
374 
375   return error;
376 }
377 
setIdleTimeout(uint32_t value)378 Return<int32_t> HWCSession::setIdleTimeout(uint32_t value) {
379   SCOPE_LOCK(locker_);
380 
381   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
382     hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(value);
383     return 0;
384   }
385 
386   return -EINVAL;
387 }
388 
getHDRCapabilities(IDisplayConfig::DisplayType dpy,getHDRCapabilities_cb _hidl_cb)389 Return<void> HWCSession::getHDRCapabilities(IDisplayConfig::DisplayType dpy,
390                                             getHDRCapabilities_cb _hidl_cb) {
391   SCOPE_LOCK(locker_);
392 
393   int32_t error = -EINVAL;
394   IDisplayConfig::DisplayHDRCapabilities hdr_caps = {};
395 
396   do {
397     int disp_id = MapDisplayType(dpy);
398     if (disp_id < 0) {
399       DLOGE("Invalid display id = %d", disp_id);
400       break;
401     }
402 
403     HWCDisplay *hwc_display = hwc_display_[disp_id];
404     if (!hwc_display) {
405       DLOGE("Display = %d is not connected.", disp_id);
406       break;
407     }
408 
409     // query number of hdr types
410     uint32_t out_num_types = 0;
411     if (hwc_display->GetHdrCapabilities(&out_num_types, nullptr, nullptr, nullptr, nullptr)
412         != HWC2::Error::None) {
413       break;
414     }
415 
416     if (!out_num_types) {
417       error = 0;
418       break;
419     }
420 
421     // query hdr caps
422     hdr_caps.supportedHdrTypes.resize(out_num_types);
423 
424     float out_max_luminance = 0.0f;
425     float out_max_average_luminance = 0.0f;
426     float out_min_luminance = 0.0f;
427     if (hwc_display->GetHdrCapabilities(&out_num_types, hdr_caps.supportedHdrTypes.data(),
428                                         &out_max_luminance, &out_max_average_luminance,
429                                         &out_min_luminance)
430         == HWC2::Error::None) {
431       error = 0;
432     }
433   } while (false);
434 
435   _hidl_cb(error, hdr_caps);
436 
437   return Void();
438 }
439 
setCameraLaunchStatus(uint32_t on)440 Return<int32_t> HWCSession::setCameraLaunchStatus(uint32_t on) {
441   SCOPE_LOCK(locker_);
442 
443   HWBwModes mode = on > 0 ? kBwCamera : kBwDefault;
444 
445   // trigger invalidate to apply new bw caps.
446   Refresh(HWC_DISPLAY_PRIMARY);
447 
448   if (core_intf_->SetMaxBandwidthMode(mode) != kErrorNone) {
449     return -EINVAL;
450   }
451 
452   new_bw_mode_ = true;
453   need_invalidate_ = true;
454   hwc_display_[HWC_DISPLAY_PRIMARY]->ResetValidation();
455 
456   return 0;
457 }
458 
DisplayBWTransactionPending(bool * status)459 int32_t HWCSession::DisplayBWTransactionPending(bool *status) {
460   SCOPE_LOCK(locker_);
461 
462   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
463     if (sync_wait(bw_mode_release_fd_, 0) < 0) {
464       DLOGI("bw_transaction_release_fd is not yet signaled: err= %s", strerror(errno));
465       *status = false;
466     }
467 
468     return 0;
469   }
470 
471   return -EINVAL;
472 }
473 
displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb)474 Return<void> HWCSession::displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb) {
475   bool status = true;
476 
477   int32_t error = DisplayBWTransactionPending(&status);
478 
479   _hidl_cb(error, status);
480 
481   return Void();
482 }
483 
484 }  // namespace sdm
485