1 /*
2 * Copyright (c) 2017-2019, 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
34 #include "hwc_buffer_sync_handler.h"
35 #include "hwc_session.h"
36
37 #define __CLASS__ "HWCSession"
38
39 namespace sdm {
40
41 using ::android::hardware::Void;
42
StartServices()43 void HWCSession::StartServices() {
44 android::status_t status = IDisplayConfig::registerAsService();
45 if (status != android::OK) {
46 DLOGW("Could not register IDisplayConfig as service (%d).", status);
47 } else {
48 DLOGI("IDisplayConfig service registration completed.");
49 }
50 }
51
MapDisplayType(IDisplayConfig::DisplayType dpy)52 int MapDisplayType(IDisplayConfig::DisplayType dpy) {
53 switch (dpy) {
54 case IDisplayConfig::DisplayType::DISPLAY_PRIMARY:
55 return HWC_DISPLAY_PRIMARY;
56
57 case IDisplayConfig::DisplayType::DISPLAY_EXTERNAL:
58 return HWC_DISPLAY_EXTERNAL;
59
60 case IDisplayConfig::DisplayType::DISPLAY_VIRTUAL:
61 return HWC_DISPLAY_VIRTUAL;
62
63 default:
64 break;
65 }
66
67 return -EINVAL;
68 }
69
MapExternalStatus(IDisplayConfig::DisplayExternalStatus status)70 HWCDisplay::DisplayStatus MapExternalStatus(IDisplayConfig::DisplayExternalStatus status) {
71 switch (status) {
72 case IDisplayConfig::DisplayExternalStatus::EXTERNAL_OFFLINE:
73 return HWCDisplay::kDisplayStatusOffline;
74
75 case IDisplayConfig::DisplayExternalStatus::EXTERNAL_ONLINE:
76 return HWCDisplay::kDisplayStatusOnline;
77
78 case IDisplayConfig::DisplayExternalStatus::EXTERNAL_PAUSE:
79 return HWCDisplay::kDisplayStatusPause;
80
81 case IDisplayConfig::DisplayExternalStatus::EXTERNAL_RESUME:
82 return HWCDisplay::kDisplayStatusResume;
83
84 default:
85 break;
86 }
87
88 return HWCDisplay::kDisplayStatusInvalid;
89 }
90
91 // Methods from ::vendor::hardware::display::config::V1_0::IDisplayConfig follow.
isDisplayConnected(IDisplayConfig::DisplayType dpy,isDisplayConnected_cb _hidl_cb)92 Return<void> HWCSession::isDisplayConnected(IDisplayConfig::DisplayType dpy,
93 isDisplayConnected_cb _hidl_cb) {
94 int32_t error = -EINVAL;
95 bool connected = false;
96 int disp_id = MapDisplayType(dpy);
97
98 if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
99 _hidl_cb(error, connected);
100 return Void();
101 }
102
103 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
104
105 connected = hwc_display_[disp_id];
106 error = 0;
107
108 _hidl_cb(error, connected);
109 return Void();
110 }
111
SetSecondaryDisplayStatus(int disp_id,HWCDisplay::DisplayStatus status)112 int32_t HWCSession::SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status) {
113 if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
114 DLOGE("Invalid display = %d", disp_id);
115 return -EINVAL;
116 }
117
118 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
119 DLOGI("Display = %d, Status = %d", disp_id, status);
120
121 if (disp_id == HWC_DISPLAY_PRIMARY) {
122 DLOGE("Not supported for this display");
123 } else if (!hwc_display_[disp_id]) {
124 DLOGW("Display is not connected");
125 } else {
126 return hwc_display_[disp_id]->SetDisplayStatus(status);
127 }
128
129 return -EINVAL;
130 }
131
setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy,IDisplayConfig::DisplayExternalStatus status)132 Return<int32_t> HWCSession::setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy,
133 IDisplayConfig::DisplayExternalStatus status) {
134 return SetSecondaryDisplayStatus(MapDisplayType(dpy), MapExternalStatus(status));
135 }
136
configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op,uint32_t refreshRate)137 Return<int32_t> HWCSession::configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op,
138 uint32_t refreshRate) {
139 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
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 if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
162 DLOGE("Invalid display = %d", disp_id);
163 return -EINVAL;
164 }
165
166 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
167
168 if (hwc_display_[disp_id]) {
169 return hwc_display_[disp_id]->GetDisplayConfigCount(count);
170 }
171
172 return -EINVAL;
173 }
174
getConfigCount(IDisplayConfig::DisplayType dpy,getConfigCount_cb _hidl_cb)175 Return<void> HWCSession::getConfigCount(IDisplayConfig::DisplayType dpy,
176 getConfigCount_cb _hidl_cb) {
177 uint32_t count = 0;
178 int32_t error = GetConfigCount(MapDisplayType(dpy), &count);
179
180 _hidl_cb(error, count);
181
182 return Void();
183 }
184
GetActiveConfigIndex(int disp_id,uint32_t * config)185 int32_t HWCSession::GetActiveConfigIndex(int disp_id, uint32_t *config) {
186 if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
187 DLOGE("Invalid display = %d", disp_id);
188 return -EINVAL;
189 }
190
191 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
192
193 if (hwc_display_[disp_id]) {
194 return hwc_display_[disp_id]->GetActiveDisplayConfig(config);
195 }
196
197 return -EINVAL;
198 }
199
getActiveConfig(IDisplayConfig::DisplayType dpy,getActiveConfig_cb _hidl_cb)200 Return<void> HWCSession::getActiveConfig(IDisplayConfig::DisplayType dpy,
201 getActiveConfig_cb _hidl_cb) {
202 uint32_t config = 0;
203 int32_t error = GetActiveConfigIndex(MapDisplayType(dpy), &config);
204
205 _hidl_cb(error, config);
206
207 return Void();
208 }
209
SetActiveConfigIndex(int disp_id,uint32_t config)210 int32_t HWCSession::SetActiveConfigIndex(int disp_id, uint32_t config) {
211 if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
212 DLOGE("Invalid display = %d", disp_id);
213 return -EINVAL;
214 }
215
216 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
217 int32_t error = -EINVAL;
218 if (hwc_display_[disp_id]) {
219 error = hwc_display_[disp_id]->SetActiveDisplayConfig(config);
220 if (!error) {
221 Refresh(0);
222 }
223 }
224
225 return error;
226 }
227
setActiveConfig(IDisplayConfig::DisplayType dpy,uint32_t config)228 Return<int32_t> HWCSession::setActiveConfig(IDisplayConfig::DisplayType dpy, uint32_t config) {
229 return SetActiveConfigIndex(MapDisplayType(dpy), config);
230 }
231
getDisplayAttributes(uint32_t configIndex,IDisplayConfig::DisplayType dpy,getDisplayAttributes_cb _hidl_cb)232 Return<void> HWCSession::getDisplayAttributes(uint32_t configIndex,
233 IDisplayConfig::DisplayType dpy,
234 getDisplayAttributes_cb _hidl_cb) {
235 int32_t error = -EINVAL;
236 IDisplayConfig::DisplayAttributes display_attributes = {};
237 int disp_id = MapDisplayType(dpy);
238
239 if (disp_id >= HWC_DISPLAY_PRIMARY && disp_id < HWC_NUM_DISPLAY_TYPES) {
240 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
241 if (hwc_display_[disp_id]) {
242 DisplayConfigVariableInfo hwc_display_attributes;
243 error = hwc_display_[disp_id]->GetDisplayAttributesForConfig(static_cast<int>(configIndex),
244 &hwc_display_attributes);
245 if (!error) {
246 display_attributes.vsyncPeriod = hwc_display_attributes.vsync_period_ns;
247 display_attributes.xRes = hwc_display_attributes.x_pixels;
248 display_attributes.yRes = hwc_display_attributes.y_pixels;
249 display_attributes.xDpi = hwc_display_attributes.x_dpi;
250 display_attributes.yDpi = hwc_display_attributes.y_dpi;
251 display_attributes.panelType = IDisplayConfig::DisplayPortType::DISPLAY_PORT_DEFAULT;
252 display_attributes.isYuv = hwc_display_attributes.is_yuv;
253 }
254 }
255 }
256 _hidl_cb(error, display_attributes);
257
258 return Void();
259 }
260
setPanelBrightness(uint32_t level)261 Return<int32_t> HWCSession::setPanelBrightness(uint32_t level) {
262 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
263 int32_t error = -EINVAL;
264
265 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
266 error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(static_cast<int>(level));
267 if (error) {
268 DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error);
269 }
270 }
271
272 return error;
273 }
274
GetPanelBrightness(int * level)275 int32_t HWCSession::GetPanelBrightness(int *level) {
276 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
277 int32_t error = -EINVAL;
278
279 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
280 error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(level);
281 if (error) {
282 DLOGE("Failed to get the panel brightness. Error = %d", error);
283 }
284 }
285
286 return error;
287 }
288
getPanelBrightness(getPanelBrightness_cb _hidl_cb)289 Return<void> HWCSession::getPanelBrightness(getPanelBrightness_cb _hidl_cb) {
290 int level = 0;
291 int32_t error = GetPanelBrightness(&level);
292
293 _hidl_cb(error, static_cast<uint32_t>(level));
294
295 return Void();
296 }
297
MinHdcpEncryptionLevelChanged(int disp_id,uint32_t min_enc_level)298 int32_t HWCSession::MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level) {
299 DLOGI("Display %d", disp_id);
300
301 if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
302 DLOGE("Invalid display = %d", disp_id);
303 return -EINVAL;
304 }
305
306 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
307 if (disp_id != HWC_DISPLAY_EXTERNAL) {
308 DLOGE("Not supported for display");
309 } else if (!hwc_display_[disp_id]) {
310 DLOGW("Display is not connected");
311 } else {
312 return hwc_display_[disp_id]->OnMinHdcpEncryptionLevelChange(min_enc_level);
313 }
314
315 return -EINVAL;
316 }
317
minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,uint32_t min_enc_level)318 Return<int32_t> HWCSession::minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,
319 uint32_t min_enc_level) {
320 return MinHdcpEncryptionLevelChanged(MapDisplayType(dpy), min_enc_level);
321 }
322
refreshScreen()323 Return<int32_t> HWCSession::refreshScreen() {
324 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
325 Refresh(HWC_DISPLAY_PRIMARY);
326
327 return 0;
328 }
329
ControlPartialUpdate(int disp_id,bool enable)330 int32_t HWCSession::ControlPartialUpdate(int disp_id, bool enable) {
331 if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
332 DLOGE("Invalid display = %d", disp_id);
333 return -EINVAL;
334 }
335
336 if (disp_id != HWC_DISPLAY_PRIMARY) {
337 DLOGW("CONTROL_PARTIAL_UPDATE is not applicable for display = %d", disp_id);
338 return -EINVAL;
339 }
340
341 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
342 HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
343 if (!hwc_display) {
344 DLOGE("primary display object is not instantiated");
345 return -EINVAL;
346 }
347
348 uint32_t pending = 0;
349 DisplayError hwc_error = hwc_display->ControlPartialUpdate(enable, &pending);
350
351 if (hwc_error == kErrorNone) {
352 if (!pending) {
353 return 0;
354 }
355 } else if (hwc_error == kErrorNotSupported) {
356 return 0;
357 } else {
358 return -EINVAL;
359 }
360
361 // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future.
362 Refresh(HWC_DISPLAY_PRIMARY);
363
364 // Wait until partial update control is complete
365 int32_t error = locker_[disp_id].WaitFinite(kCommitDoneTimeoutMs);
366
367 return error;
368 }
369
controlPartialUpdate(IDisplayConfig::DisplayType dpy,bool enable)370 Return<int32_t> HWCSession::controlPartialUpdate(IDisplayConfig::DisplayType dpy, bool enable) {
371 return ControlPartialUpdate(MapDisplayType(dpy), enable);
372 }
373
toggleScreenUpdate(bool on)374 Return<int32_t> HWCSession::toggleScreenUpdate(bool on) {
375 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
376
377 int32_t error = -EINVAL;
378 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
379 error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(on);
380 if (error) {
381 DLOGE("Failed to toggle screen updates = %d. Error = %d", on, error);
382 }
383 }
384
385 return error;
386 }
387
setIdleTimeout(uint32_t value)388 Return<int32_t> HWCSession::setIdleTimeout(uint32_t value) {
389 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
390
391 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
392 hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(value);
393 return 0;
394 }
395
396 DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
397 return -ENODEV;
398 }
399
getHDRCapabilities(IDisplayConfig::DisplayType dpy,getHDRCapabilities_cb _hidl_cb)400 Return<void> HWCSession::getHDRCapabilities(IDisplayConfig::DisplayType dpy,
401 getHDRCapabilities_cb _hidl_cb) {
402 int32_t error = -EINVAL;
403 IDisplayConfig::DisplayHDRCapabilities hdr_caps = {};
404
405 if (!_hidl_cb) {
406 DLOGE("_hidl_cb callback not provided.");
407 return Void();
408 }
409
410 do {
411 int disp_id = MapDisplayType(dpy);
412 if ((disp_id < 0) || (disp_id >= HWC_NUM_DISPLAY_TYPES)) {
413 DLOGE("Invalid display id = %d", disp_id);
414 break;
415 }
416
417 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
418 HWCDisplay *hwc_display = hwc_display_[disp_id];
419 if (!hwc_display) {
420 DLOGW("Display = %d is not connected.", disp_id);
421 error = -ENODEV;
422 break;
423 }
424
425 // query number of hdr types
426 uint32_t out_num_types = 0;
427 if (hwc_display->GetHdrCapabilities(&out_num_types, nullptr, nullptr, nullptr, nullptr)
428 != HWC2::Error::None) {
429 break;
430 }
431
432 if (!out_num_types) {
433 error = 0;
434 break;
435 }
436
437 // query hdr caps
438 hdr_caps.supportedHdrTypes.resize(out_num_types);
439
440 float out_max_luminance = 0.0f;
441 float out_max_average_luminance = 0.0f;
442 float out_min_luminance = 0.0f;
443 if (hwc_display->GetHdrCapabilities(&out_num_types, hdr_caps.supportedHdrTypes.data(),
444 &out_max_luminance, &out_max_average_luminance,
445 &out_min_luminance)
446 == HWC2::Error::None) {
447 error = 0;
448 }
449 } while (false);
450
451 _hidl_cb(error, hdr_caps);
452
453 return Void();
454 }
455
setCameraLaunchStatus(uint32_t on)456 Return<int32_t> HWCSession::setCameraLaunchStatus(uint32_t on) {
457 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
458
459 if (!core_intf_) {
460 DLOGW("core_intf_ not initialized.");
461 return -ENOENT;
462 }
463
464 if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
465 DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
466 return -ENODEV;
467 }
468
469 HWBwModes mode = on > 0 ? kBwCamera : kBwDefault;
470
471 // trigger invalidate to apply new bw caps.
472 Refresh(HWC_DISPLAY_PRIMARY);
473
474 if (core_intf_->SetMaxBandwidthMode(mode) != kErrorNone) {
475 return -EINVAL;
476 }
477
478 new_bw_mode_ = true;
479 need_invalidate_ = true;
480 hwc_display_[HWC_DISPLAY_PRIMARY]->ResetValidation();
481
482 return 0;
483 }
484
DisplayBWTransactionPending(bool * status)485 int32_t HWCSession::DisplayBWTransactionPending(bool *status) {
486 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
487
488 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
489 if (sync_wait(bw_mode_release_fd_, 0) < 0) {
490 DLOGI("bw_transaction_release_fd is not yet signaled: err= %s", strerror(errno));
491 *status = false;
492 }
493
494 return 0;
495 }
496
497 DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
498 return -ENODEV;
499 }
500
displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb)501 Return<void> HWCSession::displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb) {
502 bool status = true;
503
504 if (!_hidl_cb) {
505 DLOGE("_hidl_cb callback not provided.");
506 return Void();
507 }
508
509 int32_t error = DisplayBWTransactionPending(&status);
510
511 _hidl_cb(error, status);
512
513 return Void();
514 }
515 #ifdef DISPLAY_CONFIG_1_1
516 // Methods from ::vendor::hardware::display::config::V1_1::IDisplayConfig follow.
setDisplayAnimating(uint64_t display_id,bool animating)517 Return<int32_t> HWCSession::setDisplayAnimating(uint64_t display_id, bool animating ) {
518 return CallDisplayFunction(static_cast<hwc2_device_t *>(this), display_id,
519 &HWCDisplay::SetDisplayAnimating, animating);
520 }
521 #endif
522
523 #ifdef DISPLAY_CONFIG_1_3
controlIdlePowerCollapse(bool enable,bool synchronous)524 Return<int32_t> HWCSession::controlIdlePowerCollapse(bool enable, bool synchronous) {
525 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
526
527 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
528 if (!enable) {
529 if (!idle_pc_ref_cnt_) {
530 HWC2::Error err =
531 hwc_display_[HWC_DISPLAY_PRIMARY]->ControlIdlePowerCollapse(enable, synchronous);
532 if (err == HWC2::Error::Unsupported) {
533 return 0;
534 }
535 Refresh(HWC_DISPLAY_PRIMARY);
536 int32_t error = locker_[HWC_DISPLAY_PRIMARY].WaitFinite(kCommitDoneTimeoutMs);
537 if (error == ETIMEDOUT) {
538 DLOGE("Timed out!! Next frame commit done event not received!!");
539 return error;
540 }
541 DLOGI("Idle PC disabled!!");
542 }
543 idle_pc_ref_cnt_++;
544 } else if (idle_pc_ref_cnt_ > 0) {
545 if (!(idle_pc_ref_cnt_ - 1)) {
546 HWC2::Error err =
547 hwc_display_[HWC_DISPLAY_PRIMARY]->ControlIdlePowerCollapse(enable, synchronous);
548 if (err == HWC2::Error::Unsupported) {
549 return 0;
550 }
551 DLOGI("Idle PC enabled!!");
552 }
553 idle_pc_ref_cnt_--;
554 }
555 return 0;
556 }
557
558 DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
559 return -ENODEV;
560 }
561 #endif // DISPLAY_CONFIG_1_3
562
563 } // namespace sdm
564