1 /*
2 * Copyright (c) 2017-2020, 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 <vector>
34 #include <string>
35
36 #include "hwc_buffer_sync_handler.h"
37 #include "hwc_session.h"
38 #include "hwc_debugger.h"
39
40 #define __CLASS__ "HWCSession"
41
42 namespace sdm {
43
StartServices()44 void HWCSession::StartServices() {
45 int error = DisplayConfig::DeviceInterface::RegisterDevice(this);
46 if (error) {
47 DLOGW("Could not register IDisplayConfig as service (%d).", error);
48 } else {
49 DLOGI("IDisplayConfig service registration completed.");
50 }
51 }
52
MapDisplayType(DispType dpy)53 int MapDisplayType(DispType dpy) {
54 switch (dpy) {
55 case DispType::kPrimary:
56 return qdutils::DISPLAY_PRIMARY;
57
58 case DispType::kExternal:
59 return qdutils::DISPLAY_EXTERNAL;
60
61 case DispType::kVirtual:
62 return qdutils::DISPLAY_VIRTUAL;
63
64 default:
65 break;
66 }
67
68 return -EINVAL;
69 }
70
WaitForResourceNeeded(HWC2::PowerMode prev_mode,HWC2::PowerMode new_mode)71 bool WaitForResourceNeeded(HWC2::PowerMode prev_mode, HWC2::PowerMode new_mode) {
72 return ((prev_mode == HWC2::PowerMode::Off) &&
73 (new_mode == HWC2::PowerMode::On || new_mode == HWC2::PowerMode::Doze));
74 }
75
MapExternalStatus(DisplayConfig::ExternalStatus status)76 HWCDisplay::DisplayStatus MapExternalStatus(DisplayConfig::ExternalStatus status) {
77 switch (status) {
78 case DisplayConfig::ExternalStatus::kOffline:
79 return HWCDisplay::kDisplayStatusOffline;
80
81 case DisplayConfig::ExternalStatus::kOnline:
82 return HWCDisplay::kDisplayStatusOnline;
83
84 case DisplayConfig::ExternalStatus::kPause:
85 return HWCDisplay::kDisplayStatusPause;
86
87 case DisplayConfig::ExternalStatus::kResume:
88 return HWCDisplay::kDisplayStatusResume;
89
90 default:
91 break;
92 }
93
94 return HWCDisplay::kDisplayStatusInvalid;
95 }
96
RegisterClientContext(std::shared_ptr<DisplayConfig::ConfigCallback> callback,DisplayConfig::ConfigInterface ** intf)97 int HWCSession::RegisterClientContext(std::shared_ptr<DisplayConfig::ConfigCallback> callback,
98 DisplayConfig::ConfigInterface **intf) {
99 if (!intf) {
100 DLOGE("Invalid DisplayConfigIntf location");
101 return -EINVAL;
102 }
103
104 std::weak_ptr<DisplayConfig::ConfigCallback> wp_callback = callback;
105 DisplayConfigImpl *impl = new DisplayConfigImpl(wp_callback, this);
106 *intf = impl;
107
108 return 0;
109 }
110
UnRegisterClientContext(DisplayConfig::ConfigInterface * intf)111 void HWCSession::UnRegisterClientContext(DisplayConfig::ConfigInterface *intf) {
112 delete static_cast<DisplayConfigImpl *>(intf);
113 }
114
DisplayConfigImpl(std::weak_ptr<DisplayConfig::ConfigCallback> callback,HWCSession * hwc_session)115 HWCSession::DisplayConfigImpl::DisplayConfigImpl(
116 std::weak_ptr<DisplayConfig::ConfigCallback> callback,
117 HWCSession *hwc_session) {
118 callback_ = callback;
119 hwc_session_ = hwc_session;
120 }
121
IsDisplayConnected(DispType dpy,bool * connected)122 int HWCSession::DisplayConfigImpl::IsDisplayConnected(DispType dpy, bool *connected) {
123 int disp_id = MapDisplayType(dpy);
124 int disp_idx = hwc_session_->GetDisplayIndex(disp_id);
125
126 if (disp_idx == -1) {
127 DLOGE("Invalid display = %d", disp_id);
128 return -EINVAL;
129 } else {
130 SEQUENCE_WAIT_SCOPE_LOCK(hwc_session_->locker_[disp_idx]);
131 *connected = hwc_session_->hwc_display_[disp_idx];
132 }
133
134 return 0;
135 }
136
SetDisplayStatus(int disp_id,HWCDisplay::DisplayStatus status)137 int HWCSession::SetDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status) {
138 int disp_idx = GetDisplayIndex(disp_id);
139 int err = -EINVAL;
140 if (disp_idx == -1) {
141 DLOGE("Invalid display = %d", disp_id);
142 return -EINVAL;
143 }
144
145 if (disp_idx == qdutils::DISPLAY_PRIMARY) {
146 DLOGE("Not supported for this display");
147 return err;
148 }
149
150 {
151 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_idx]);
152 if (!hwc_display_[disp_idx]) {
153 DLOGW("Display is not connected");
154 return err;
155 }
156 DLOGI("Display = %d, Status = %d", disp_idx, status);
157 err = hwc_display_[disp_idx]->SetDisplayStatus(status);
158 if (err != 0) {
159 return err;
160 }
161 }
162
163 if (status == HWCDisplay::kDisplayStatusResume || status == HWCDisplay::kDisplayStatusPause) {
164 hwc2_display_t active_builtin_disp_id = GetActiveBuiltinDisplay();
165 if (active_builtin_disp_id < HWCCallbacks::kNumRealDisplays) {
166 {
167 SEQUENCE_WAIT_SCOPE_LOCK(locker_[active_builtin_disp_id]);
168 hwc_display_[active_builtin_disp_id]->ResetValidation();
169 }
170 callbacks_.Refresh(active_builtin_disp_id);
171 }
172 }
173
174 return err;
175 }
176
SetDisplayStatus(DispType dpy,DisplayConfig::ExternalStatus status)177 int HWCSession::DisplayConfigImpl::SetDisplayStatus(DispType dpy,
178 DisplayConfig::ExternalStatus status) {
179 return hwc_session_->SetDisplayStatus(MapDisplayType(dpy), MapExternalStatus(status));
180 }
181
ConfigureDynRefreshRate(DisplayConfig::DynRefreshRateOp op,uint32_t refresh_rate)182 int HWCSession::DisplayConfigImpl::ConfigureDynRefreshRate(DisplayConfig::DynRefreshRateOp op,
183 uint32_t refresh_rate) {
184 SEQUENCE_WAIT_SCOPE_LOCK(hwc_session_->locker_[HWC_DISPLAY_PRIMARY]);
185 HWCDisplay *hwc_display = hwc_session_->hwc_display_[HWC_DISPLAY_PRIMARY];
186
187 if (!hwc_display) {
188 DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
189 return -EINVAL;
190 }
191
192 switch (op) {
193 case DisplayConfig::DynRefreshRateOp::kDisableMetadata:
194 return hwc_display->Perform(HWCDisplayBuiltIn::SET_METADATA_DYN_REFRESH_RATE, false);
195
196 case DisplayConfig::DynRefreshRateOp::kEnableMetadata:
197 return hwc_display->Perform(HWCDisplayBuiltIn::SET_METADATA_DYN_REFRESH_RATE, true);
198
199 case DisplayConfig::DynRefreshRateOp::kSetBinder:
200 return hwc_display->Perform(HWCDisplayBuiltIn::SET_BINDER_DYN_REFRESH_RATE, refresh_rate);
201
202 default:
203 DLOGW("Invalid operation %d", op);
204 return -EINVAL;
205 }
206
207 return 0;
208 }
209
GetConfigCount(int disp_id,uint32_t * count)210 int HWCSession::GetConfigCount(int disp_id, uint32_t *count) {
211 int disp_idx = GetDisplayIndex(disp_id);
212 if (disp_idx == -1) {
213 DLOGE("Invalid display = %d", disp_id);
214 return -EINVAL;
215 }
216
217 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_idx]);
218
219 if (hwc_display_[disp_idx]) {
220 return hwc_display_[disp_idx]->GetDisplayConfigCount(count);
221 }
222
223 return -EINVAL;
224 }
225
GetConfigCount(DispType dpy,uint32_t * count)226 int HWCSession::DisplayConfigImpl::GetConfigCount(DispType dpy, uint32_t *count) {
227 return hwc_session_->GetConfigCount(MapDisplayType(dpy), count);
228 }
229
GetActiveConfigIndex(int disp_id,uint32_t * config)230 int HWCSession::GetActiveConfigIndex(int disp_id, uint32_t *config) {
231 int disp_idx = GetDisplayIndex(disp_id);
232 if (disp_idx == -1) {
233 DLOGE("Invalid display = %d", disp_id);
234 return -EINVAL;
235 }
236
237 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_idx]);
238
239 if (hwc_display_[disp_idx]) {
240 return hwc_display_[disp_idx]->GetActiveDisplayConfig(config);
241 }
242
243 return -EINVAL;
244 }
245
GetActiveConfig(DispType dpy,uint32_t * config)246 int HWCSession::DisplayConfigImpl::GetActiveConfig(DispType dpy, uint32_t *config) {
247 return hwc_session_->GetActiveConfigIndex(MapDisplayType(dpy), config);
248 }
249
SetActiveConfigIndex(int disp_id,uint32_t config)250 int HWCSession::SetActiveConfigIndex(int disp_id, uint32_t config) {
251 int disp_idx = GetDisplayIndex(disp_id);
252 if (disp_idx == -1) {
253 DLOGE("Invalid display = %d", disp_id);
254 return -EINVAL;
255 }
256
257 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_idx]);
258 int error = -EINVAL;
259 if (hwc_display_[disp_idx]) {
260 error = hwc_display_[disp_idx]->SetActiveDisplayConfig(config);
261 if (!error) {
262 callbacks_.Refresh(0);
263 }
264 }
265
266 return error;
267 }
268
SetActiveConfig(DispType dpy,uint32_t config)269 int HWCSession::DisplayConfigImpl::SetActiveConfig(DispType dpy, uint32_t config) {
270 return hwc_session_->SetActiveConfigIndex(MapDisplayType(dpy), config);
271 }
272
GetDisplayAttributes(uint32_t config_index,DispType dpy,DisplayConfig::Attributes * attributes)273 int HWCSession::DisplayConfigImpl::GetDisplayAttributes(uint32_t config_index, DispType dpy,
274 DisplayConfig::Attributes *attributes) {
275 int error = -EINVAL;
276 int disp_id = MapDisplayType(dpy);
277 int disp_idx = hwc_session_->GetDisplayIndex(disp_id);
278
279 if (disp_idx == -1) {
280 DLOGE("Invalid display = %d", disp_id);
281 } else {
282 SEQUENCE_WAIT_SCOPE_LOCK(hwc_session_->locker_[disp_idx]);
283 if (hwc_session_->hwc_display_[disp_idx]) {
284 DisplayConfigVariableInfo var_info;
285 error = hwc_session_->hwc_display_[disp_idx]->GetDisplayAttributesForConfig(INT(config_index),
286 &var_info);
287 if (!error) {
288 attributes->vsync_period = var_info.vsync_period_ns;
289 attributes->x_res = var_info.x_pixels;
290 attributes->y_res = var_info.y_pixels;
291 attributes->x_dpi = var_info.x_dpi;
292 attributes->y_dpi = var_info.y_dpi;
293 attributes->panel_type = DisplayConfig::DisplayPortType::kDefault;
294 attributes->is_yuv = var_info.is_yuv;
295 }
296 }
297 }
298
299 return error;
300 }
301
SetPanelBrightness(uint32_t level)302 int HWCSession::DisplayConfigImpl::SetPanelBrightness(uint32_t level) {
303 if (!(0 <= level && level <= 255)) {
304 return -EINVAL;
305 }
306
307 if (level == 0) {
308 return INT32(hwc_session_->SetDisplayBrightness(HWC_DISPLAY_PRIMARY, -1.0f));
309 } else {
310 return INT32(hwc_session_->SetDisplayBrightness(HWC_DISPLAY_PRIMARY, (level - 1)/254.0f));
311 }
312 }
313
GetPanelBrightness(uint32_t * level)314 int HWCSession::DisplayConfigImpl::GetPanelBrightness(uint32_t *level) {
315 float brightness = -1.0f;
316 int error = -EINVAL;
317
318 error = hwc_session_->getDisplayBrightness(HWC_DISPLAY_PRIMARY, &brightness);
319 if (brightness == -1.0f) {
320 *level = 0;
321 } else {
322 *level = static_cast<uint32_t>(254.0f*brightness + 1);
323 }
324
325 return error;
326 }
327
MinHdcpEncryptionLevelChanged(int disp_id,uint32_t min_enc_level)328 int HWCSession::MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level) {
329 DLOGI("Display %d", disp_id);
330
331 // SSG team hardcoded disp_id as external because it applies to external only but SSG team sends
332 // this level irrespective of external connected or not. So to honor the call, make disp_id to
333 // primary & set level.
334 disp_id = HWC_DISPLAY_PRIMARY;
335 int disp_idx = GetDisplayIndex(disp_id);
336 if (disp_idx == -1) {
337 DLOGE("Invalid display = %d", disp_id);
338 return -EINVAL;
339 }
340
341 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_idx]);
342 HWCDisplay *hwc_display = hwc_display_[disp_idx];
343 if (!hwc_display) {
344 DLOGE("Display = %d is not connected.", disp_idx);
345 return -EINVAL;
346 }
347
348 return hwc_display->OnMinHdcpEncryptionLevelChange(min_enc_level);
349 }
350
MinHdcpEncryptionLevelChanged(DispType dpy,uint32_t min_enc_level)351 int HWCSession::DisplayConfigImpl::MinHdcpEncryptionLevelChanged(DispType dpy,
352 uint32_t min_enc_level) {
353 return hwc_session_->MinHdcpEncryptionLevelChanged(MapDisplayType(dpy), min_enc_level);
354 }
355
RefreshScreen()356 int HWCSession::DisplayConfigImpl::RefreshScreen() {
357 SEQUENCE_WAIT_SCOPE_LOCK(hwc_session_->locker_[HWC_DISPLAY_PRIMARY]);
358 hwc_session_->callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
359 return 0;
360 }
361
ControlPartialUpdate(int disp_id,bool enable)362 int HWCSession::ControlPartialUpdate(int disp_id, bool enable) {
363 int disp_idx = GetDisplayIndex(disp_id);
364 if (disp_idx == -1) {
365 DLOGE("Invalid display = %d", disp_id);
366 return -EINVAL;
367 }
368
369 if (disp_idx != HWC_DISPLAY_PRIMARY) {
370 DLOGW("CONTROL_PARTIAL_UPDATE is not applicable for display = %d", disp_idx);
371 return -EINVAL;
372 }
373
374 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_idx]);
375 HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
376 if (!hwc_display) {
377 DLOGE("primary display object is not instantiated");
378 return -EINVAL;
379 }
380
381 uint32_t pending = 0;
382 DisplayError hwc_error = hwc_display->ControlPartialUpdate(enable, &pending);
383
384 if (hwc_error == kErrorNone) {
385 if (!pending) {
386 return 0;
387 }
388 } else if (hwc_error == kErrorNotSupported) {
389 return 0;
390 } else {
391 return -EINVAL;
392 }
393
394 // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future.
395 callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
396
397 // Wait until partial update control is complete
398 int error = locker_[disp_idx].WaitFinite(kCommitDoneTimeoutMs);
399
400 return error;
401 }
402
ControlPartialUpdate(DispType dpy,bool enable)403 int HWCSession::DisplayConfigImpl::ControlPartialUpdate(DispType dpy, bool enable) {
404 return hwc_session_->ControlPartialUpdate(MapDisplayType(dpy), enable);
405 }
406
ToggleScreenUpdate(bool on)407 int HWCSession::ToggleScreenUpdate(bool on) {
408 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
409
410 int error = -EINVAL;
411 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
412 error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(on);
413 if (error) {
414 DLOGE("Failed to toggle screen updates = %d. Error = %d", on, error);
415 }
416 }
417
418 return error;
419 }
420
ToggleScreenUpdate(bool on)421 int HWCSession::DisplayConfigImpl::ToggleScreenUpdate(bool on) {
422 return hwc_session_->ToggleScreenUpdate(on);
423 }
424
SetIdleTimeout(uint32_t value)425 int HWCSession::SetIdleTimeout(uint32_t value) {
426 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
427
428 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
429 hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(value);
430 return 0;
431 }
432
433 DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
434 return -ENODEV;
435 }
436
SetIdleTimeout(uint32_t value)437 int HWCSession::DisplayConfigImpl::SetIdleTimeout(uint32_t value) {
438 return hwc_session_->SetIdleTimeout(value);
439 }
440
GetHDRCapabilities(DispType dpy,DisplayConfig::HDRCapsParams * caps)441 int HWCSession::DisplayConfigImpl::GetHDRCapabilities(DispType dpy,
442 DisplayConfig::HDRCapsParams *caps) {
443 int error = -EINVAL;
444
445 do {
446 int disp_id = MapDisplayType(dpy);
447 int disp_idx = hwc_session_->GetDisplayIndex(disp_id);
448 if (disp_idx == -1) {
449 DLOGE("Invalid display = %d", disp_id);
450 break;
451 }
452
453 SCOPE_LOCK(hwc_session_->locker_[disp_id]);
454 HWCDisplay *hwc_display = hwc_session_->hwc_display_[disp_idx];
455 if (!hwc_display) {
456 DLOGW("Display = %d is not connected.", disp_idx);
457 error = -ENODEV;
458 break;
459 }
460
461 // query number of hdr types
462 uint32_t out_num_types = 0;
463 float out_max_luminance = 0.0f;
464 float out_max_average_luminance = 0.0f;
465 float out_min_luminance = 0.0f;
466 if (hwc_display->GetHdrCapabilities(&out_num_types, nullptr, &out_max_luminance,
467 &out_max_average_luminance, &out_min_luminance)
468 != HWC2::Error::None) {
469 break;
470 }
471 if (!out_num_types) {
472 error = 0;
473 break;
474 }
475
476 // query hdr caps
477 caps->supported_hdr_types.resize(out_num_types);
478
479 if (hwc_display->GetHdrCapabilities(&out_num_types, caps->supported_hdr_types.data(),
480 &out_max_luminance, &out_max_average_luminance,
481 &out_min_luminance) == HWC2::Error::None) {
482 error = 0;
483 }
484 } while (false);
485
486 return error;
487 }
488
SetCameraLaunchStatus(uint32_t on)489 int HWCSession::SetCameraLaunchStatus(uint32_t on) {
490 if (null_display_mode_) {
491 return 0;
492 }
493
494 if (!core_intf_) {
495 DLOGW("core_intf_ not initialized.");
496 return -ENOENT;
497 }
498
499 HWBwModes mode = on > 0 ? kBwVFEOn : kBwVFEOff;
500
501 if (core_intf_->SetMaxBandwidthMode(mode) != kErrorNone) {
502 return -EINVAL;
503 }
504
505 // trigger invalidate to apply new bw caps.
506 callbacks_.Refresh(0);
507
508 return 0;
509 }
510
SetCameraLaunchStatus(uint32_t on)511 int HWCSession::DisplayConfigImpl::SetCameraLaunchStatus(uint32_t on) {
512 return hwc_session_->SetCameraLaunchStatus(on);
513 }
514
DisplayBWTransactionPending(bool * status)515 int HWCSession::DisplayBWTransactionPending(bool *status) {
516 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
517
518 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
519 if (sync_wait(bw_mode_release_fd_, 0) < 0) {
520 DLOGI("bw_transaction_release_fd is not yet signaled: err= %s", strerror(errno));
521 *status = false;
522 }
523
524 return 0;
525 }
526
527 DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
528 return -ENODEV;
529 }
530
DisplayBWTransactionPending(bool * status)531 int HWCSession::DisplayConfigImpl::DisplayBWTransactionPending(bool *status) {
532 return hwc_session_->DisplayBWTransactionPending(status);
533 }
534
ControlIdlePowerCollapse(bool enable,bool synchronous)535 int HWCSession::ControlIdlePowerCollapse(bool enable, bool synchronous) {
536 hwc2_display_t active_builtin_disp_id = GetActiveBuiltinDisplay();
537 if (active_builtin_disp_id >= HWCCallbacks::kNumDisplays) {
538 DLOGE("No active displays");
539 return -EINVAL;
540 }
541 SEQUENCE_WAIT_SCOPE_LOCK(locker_[active_builtin_disp_id]);
542
543 if (hwc_display_[active_builtin_disp_id]) {
544 if (!enable) {
545 if (!idle_pc_ref_cnt_) {
546 auto err = hwc_display_[active_builtin_disp_id]->ControlIdlePowerCollapse(enable,
547 synchronous);
548 if (err != kErrorNone) {
549 return (err == kErrorNotSupported) ? 0 : -EINVAL;
550 }
551 callbacks_.Refresh(active_builtin_disp_id);
552 int error = locker_[active_builtin_disp_id].WaitFinite(kCommitDoneTimeoutMs);
553 if (error == ETIMEDOUT) {
554 DLOGE("Timed out!! Next frame commit done event not received!!");
555 return error;
556 }
557 DLOGI("Idle PC disabled!!");
558 }
559 idle_pc_ref_cnt_++;
560 } else if (idle_pc_ref_cnt_ > 0) {
561 if (!(idle_pc_ref_cnt_ - 1)) {
562 auto err = hwc_display_[active_builtin_disp_id]->ControlIdlePowerCollapse(enable,
563 synchronous);
564 if (err != kErrorNone) {
565 return (err == kErrorNotSupported) ? 0 : -EINVAL;
566 }
567 DLOGI("Idle PC enabled!!");
568 }
569 idle_pc_ref_cnt_--;
570 }
571 return 0;
572 }
573
574 DLOGW("Display = %d is not connected.", UINT32(active_builtin_disp_id));
575 return -ENODEV;
576 }
577
ControlIdlePowerCollapse(bool enable,bool synchronous)578 int HWCSession::DisplayConfigImpl::ControlIdlePowerCollapse(bool enable, bool synchronous) {
579 return hwc_session_->ControlIdlePowerCollapse(enable, synchronous);
580 }
581
IsWbUbwcSupported(bool * value)582 int HWCSession::IsWbUbwcSupported(bool *value) {
583 HWDisplaysInfo hw_displays_info = {};
584 DisplayError error = core_intf_->GetDisplaysStatus(&hw_displays_info);
585 if (error != kErrorNone) {
586 return -EINVAL;
587 }
588
589 for (auto &iter : hw_displays_info) {
590 auto &info = iter.second;
591 if (info.display_type == kVirtual && info.is_wb_ubwc_supported) {
592 *value = 1;
593 }
594 }
595
596 return error;
597 }
598
getDisplayBrightness(uint32_t display,float * brightness)599 int32_t HWCSession::getDisplayBrightness(uint32_t display, float *brightness) {
600 if (!brightness) {
601 return HWC2_ERROR_BAD_PARAMETER;
602 }
603
604 if (display >= HWCCallbacks::kNumDisplays) {
605 return HWC2_ERROR_BAD_DISPLAY;
606 }
607
608 SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
609 int32_t error = -EINVAL;
610 *brightness = -1.0f;
611
612 HWCDisplay *hwc_display = hwc_display_[display];
613 if (hwc_display && hwc_display_[display]->GetDisplayClass() == DISPLAY_CLASS_BUILTIN) {
614 error = INT32(hwc_display_[display]->GetPanelBrightness(brightness));
615 if (error) {
616 DLOGE("Failed to get the panel brightness. Error = %d", error);
617 }
618 }
619
620 return error;
621 }
622
getDisplayMaxBrightness(uint32_t display,uint32_t * max_brightness_level)623 int32_t HWCSession::getDisplayMaxBrightness(uint32_t display, uint32_t *max_brightness_level) {
624 if (!max_brightness_level) {
625 return HWC2_ERROR_BAD_PARAMETER;
626 }
627
628 if (display >= HWCCallbacks::kNumDisplays) {
629 return HWC2_ERROR_BAD_DISPLAY;
630 }
631
632 int32_t error = -EINVAL;
633 HWCDisplay *hwc_display = hwc_display_[display];
634 if (hwc_display && hwc_display_[display]->GetDisplayClass() == DISPLAY_CLASS_BUILTIN) {
635 error = INT32(hwc_display_[display]->GetPanelMaxBrightness(max_brightness_level));
636 if (error) {
637 DLOGE("Failed to get the panel max brightness, display %u error %d", display, error);
638 }
639 }
640
641 return error;
642 }
643
SetDisplayAnimating(uint64_t display_id,bool animating)644 int HWCSession::DisplayConfigImpl::SetDisplayAnimating(uint64_t display_id, bool animating) {
645 return hwc_session_->CallDisplayFunction(display_id, &HWCDisplay::SetDisplayAnimating, animating);
646 }
647
GetWriteBackCapabilities(bool * isWbUbwcSupported)648 int HWCSession::DisplayConfigImpl::GetWriteBackCapabilities(bool *isWbUbwcSupported) {
649 return hwc_session_->IsWbUbwcSupported(isWbUbwcSupported);
650 }
651
SetDisplayDppsAdROI(uint32_t display_id,uint32_t h_start,uint32_t h_end,uint32_t v_start,uint32_t v_end,uint32_t factor_in,uint32_t factor_out)652 int HWCSession::SetDisplayDppsAdROI(uint32_t display_id, uint32_t h_start,
653 uint32_t h_end, uint32_t v_start, uint32_t v_end,
654 uint32_t factor_in, uint32_t factor_out) {
655 return CallDisplayFunction(display_id,
656 &HWCDisplay::SetDisplayDppsAdROI, h_start, h_end, v_start, v_end,
657 factor_in, factor_out);
658 }
659
SetDisplayDppsAdROI(uint32_t display_id,uint32_t h_start,uint32_t h_end,uint32_t v_start,uint32_t v_end,uint32_t factor_in,uint32_t factor_out)660 int HWCSession::DisplayConfigImpl::SetDisplayDppsAdROI(uint32_t display_id, uint32_t h_start,
661 uint32_t h_end, uint32_t v_start,
662 uint32_t v_end, uint32_t factor_in,
663 uint32_t factor_out) {
664 return hwc_session_->SetDisplayDppsAdROI(display_id, h_start, h_end, v_start, v_end,
665 factor_in, factor_out);
666 }
667
UpdateVSyncSourceOnPowerModeOff()668 int HWCSession::DisplayConfigImpl::UpdateVSyncSourceOnPowerModeOff() {
669 hwc_session_->update_vsync_on_power_off_ = true;
670 return 0;
671 }
672
UpdateVSyncSourceOnPowerModeDoze()673 int HWCSession::DisplayConfigImpl::UpdateVSyncSourceOnPowerModeDoze() {
674 hwc_session_->update_vsync_on_doze_ = true;
675 return 0;
676 }
677
IsPowerModeOverrideSupported(uint32_t disp_id,bool * supported)678 int HWCSession::DisplayConfigImpl::IsPowerModeOverrideSupported(uint32_t disp_id,
679 bool *supported) {
680 if (!hwc_session_->async_powermode_ || (disp_id > HWCCallbacks::kNumRealDisplays)) {
681 *supported = false;
682 } else {
683 *supported = true;
684 }
685
686 return 0;
687 }
688
SetPowerMode(uint32_t disp_id,DisplayConfig::PowerMode power_mode)689 int HWCSession::DisplayConfigImpl::SetPowerMode(uint32_t disp_id,
690 DisplayConfig::PowerMode power_mode) {
691 SCOPE_LOCK(hwc_session_->display_config_locker_);
692
693 bool supported = false;
694 IsPowerModeOverrideSupported(disp_id, &supported);
695 if (!supported) {
696 return 0;
697 }
698
699 // Active builtin display needs revalidation
700 hwc2_display_t active_builtin_disp_id = hwc_session_->GetActiveBuiltinDisplay();
701 HWC2::PowerMode previous_mode = hwc_session_->hwc_display_[disp_id]->GetCurrentPowerMode();
702
703 DLOGI("disp_id: %d power_mode: %d", disp_id, power_mode);
704 HWCDisplay::HWCLayerStack stack = {};
705 hwc2_display_t dummy_disp_id = hwc_session_->map_hwc_display_.at(disp_id);
706
707 // Power state transition start.
708 // Acquire the display's power-state transition var read lock.
709 hwc_session_->power_state_[disp_id].Lock();
710 hwc_session_->power_state_transition_[disp_id] = true;
711 hwc_session_->locker_[disp_id].Lock(); // Lock the real display.
712 hwc_session_->locker_[dummy_disp_id].Lock(); // Lock the corresponding dummy display.
713
714 // Place the real display's layer-stack on the dummy display.
715 hwc_session_->hwc_display_[disp_id]->GetLayerStack(&stack);
716 hwc_session_->hwc_display_[dummy_disp_id]->SetLayerStack(&stack);
717 hwc_session_->hwc_display_[dummy_disp_id]->UpdatePowerMode(
718 hwc_session_->hwc_display_[disp_id]->GetCurrentPowerMode());
719
720 hwc_session_->locker_[dummy_disp_id].Unlock(); // Release the dummy display.
721 // Release the display's power-state transition var read lock.
722 hwc_session_->power_state_[disp_id].Unlock();
723
724 // From now, till power-state transition ends, for operations that need to be non-blocking, do
725 // those operations on the dummy display.
726
727 // Perform the actual [synchronous] power-state change.
728 hwc_session_->hwc_display_[disp_id]->SetPowerMode(static_cast<HWC2::PowerMode>(power_mode),
729 false /* teardown */);
730
731 // Power state transition end.
732 // Acquire the display's power-state transition var read lock.
733 hwc_session_->power_state_[disp_id].Lock();
734 hwc_session_->power_state_transition_[disp_id] = false;
735 hwc_session_->locker_[dummy_disp_id].Lock(); // Lock the dummy display.
736
737 // Retrieve the real display's layer-stack from the dummy display.
738 hwc_session_->hwc_display_[dummy_disp_id]->GetLayerStack(&stack);
739 hwc_session_->hwc_display_[disp_id]->SetLayerStack(&stack);
740 // Read display has got layerstack. Update the fences.
741 hwc_session_->hwc_display_[disp_id]->PostPowerMode();
742
743 hwc_session_->locker_[dummy_disp_id].Unlock(); // Release the dummy display.
744 hwc_session_->locker_[disp_id].Unlock(); // Release the real display.
745 // Release the display's power-state transition var read lock.
746 hwc_session_->power_state_[disp_id].Unlock();
747
748 HWC2::PowerMode new_mode = hwc_session_->hwc_display_[disp_id]->GetCurrentPowerMode();
749 if (active_builtin_disp_id < HWCCallbacks::kNumRealDisplays &&
750 hwc_session_->hwc_display_[disp_id]->IsFirstCommitDone() &&
751 WaitForResourceNeeded(previous_mode, new_mode)) {
752 hwc_session_->WaitForResources(true, active_builtin_disp_id, disp_id);
753 }
754
755 return 0;
756 }
757
IsHDRSupported(uint32_t disp_id,bool * supported)758 int HWCSession::DisplayConfigImpl::IsHDRSupported(uint32_t disp_id, bool *supported) {
759 if (disp_id < 0 || disp_id >= HWCCallbacks::kNumDisplays) {
760 DLOGE("Not valid display");
761 return -EINVAL;
762 }
763 SCOPE_LOCK(hwc_session_->hdr_locker_[disp_id]);
764
765 if (hwc_session_->is_hdr_display_.size() <= disp_id) {
766 DLOGW("is_hdr_display_ is not initialized for display %d!! Reporting it as HDR not supported",
767 disp_id);
768 *supported = false;
769 return 0;
770 }
771
772 *supported = static_cast<bool>(hwc_session_->is_hdr_display_[disp_id]);
773 return 0;
774 }
775
IsWCGSupported(uint32_t disp_id,bool * supported)776 int HWCSession::DisplayConfigImpl::IsWCGSupported(uint32_t disp_id, bool *supported) {
777 // todo(user): Query wcg from sdm. For now assume them same.
778 return IsHDRSupported(disp_id, supported);
779 }
780
SetLayerAsMask(uint32_t disp_id,uint64_t layer_id)781 int HWCSession::DisplayConfigImpl::SetLayerAsMask(uint32_t disp_id, uint64_t layer_id) {
782 SCOPE_LOCK(hwc_session_->locker_[disp_id]);
783 HWCDisplay *hwc_display = hwc_session_->hwc_display_[disp_id];
784 if (!hwc_display) {
785 DLOGW("Display = %d is not connected.", disp_id);
786 return -EINVAL;
787 }
788
789 if (hwc_session_->disable_mask_layer_hint_) {
790 DLOGW("Mask layer hint is disabled!");
791 return -EINVAL;
792 }
793
794 auto hwc_layer = hwc_display->GetHWCLayer(layer_id);
795 if (hwc_layer == nullptr) {
796 return -EINVAL;
797 }
798
799 hwc_layer->SetLayerAsMask();
800
801 return 0;
802 }
803
GetDebugProperty(const std::string prop_name,std::string * value)804 int HWCSession::DisplayConfigImpl::GetDebugProperty(const std::string prop_name,
805 std::string *value) {
806 std::string vendor_prop_name = DISP_PROP_PREFIX;
807 int error = -EINVAL;
808 char val[64] = {};
809
810 vendor_prop_name += prop_name.c_str();
811 if (HWCDebugHandler::Get()->GetProperty(vendor_prop_name.c_str(), val) == kErrorNone) {
812 *value = val;
813 error = 0;
814 }
815
816 return error;
817 }
818
GetActiveBuiltinDisplayAttributes(DisplayConfig::Attributes * attr)819 int HWCSession::DisplayConfigImpl::GetActiveBuiltinDisplayAttributes(
820 DisplayConfig::Attributes *attr) {
821 int error = -EINVAL;
822 hwc2_display_t disp_id = hwc_session_->GetActiveBuiltinDisplay();
823
824 if (disp_id >= HWCCallbacks::kNumDisplays) {
825 DLOGE("Invalid display = %d", UINT32(disp_id));
826 } else {
827 if (hwc_session_->hwc_display_[disp_id]) {
828 uint32_t config_index = 0;
829 HWC2::Error ret = hwc_session_->hwc_display_[disp_id]->GetActiveConfig(&config_index);
830 if (ret != HWC2::Error::None) {
831 goto err;
832 }
833 DisplayConfigVariableInfo var_info;
834 error = hwc_session_->hwc_display_[disp_id]->GetDisplayAttributesForConfig(INT(config_index),
835 &var_info);
836 if (!error) {
837 attr->vsync_period = var_info.vsync_period_ns;
838 attr->x_res = var_info.x_pixels;
839 attr->y_res = var_info.y_pixels;
840 attr->x_dpi = var_info.x_dpi;
841 attr->y_dpi = var_info.y_dpi;
842 attr->panel_type = DisplayConfig::DisplayPortType::kDefault;
843 attr->is_yuv = var_info.is_yuv;
844 }
845 }
846 }
847
848 err:
849 return error;
850 }
851
SetPanelLuminanceAttributes(uint32_t disp_id,float pan_min_lum,float pan_max_lum)852 int HWCSession::DisplayConfigImpl::SetPanelLuminanceAttributes(uint32_t disp_id, float pan_min_lum,
853 float pan_max_lum) {
854 // currently doing only for virtual display
855 if (disp_id != qdutils::DISPLAY_VIRTUAL) {
856 return -EINVAL;
857 }
858
859 // check for out of range luminance values
860 if (pan_min_lum <= 0.0f || pan_min_lum >= 1.0f ||
861 pan_max_lum <= 100.0f || pan_max_lum >= 1000.0f) {
862 return -EINVAL;
863 }
864
865 std::lock_guard<std::mutex> obj(hwc_session_->mutex_lum_);
866 hwc_session_->set_min_lum_ = pan_min_lum;
867 hwc_session_->set_max_lum_ = pan_max_lum;
868 DLOGI("set max_lum %f, min_lum %f", pan_max_lum, pan_min_lum);
869
870 return 0;
871 }
872
IsBuiltInDisplay(uint32_t disp_id,bool * is_builtin)873 int HWCSession::DisplayConfigImpl::IsBuiltInDisplay(uint32_t disp_id, bool *is_builtin) {
874 if ((hwc_session_->map_info_primary_.client_id == disp_id) &&
875 (hwc_session_->map_info_primary_.disp_type == kBuiltIn)) {
876 *is_builtin = true;
877 return 0;
878 }
879
880 for (auto &info : hwc_session_->map_info_builtin_) {
881 if (disp_id == info.client_id) {
882 *is_builtin = true;
883 return 0;
884 }
885 }
886
887 *is_builtin = false;
888 return 0;
889 }
890
GetSupportedDSIBitClks(uint32_t disp_id,std::vector<uint64_t> * bit_clks)891 int HWCSession::DisplayConfigImpl::GetSupportedDSIBitClks(uint32_t disp_id,
892 std::vector<uint64_t> *bit_clks) {
893 SCOPE_LOCK(hwc_session_->locker_[disp_id]);
894 if (!hwc_session_->hwc_display_[disp_id]) {
895 return -EINVAL;
896 }
897
898 hwc_session_->hwc_display_[disp_id]->GetSupportedDSIClock(bit_clks);
899 return 0;
900 }
901
GetDSIClk(uint32_t disp_id,uint64_t * bit_clk)902 int HWCSession::DisplayConfigImpl::GetDSIClk(uint32_t disp_id, uint64_t *bit_clk) {
903 SCOPE_LOCK(hwc_session_->locker_[disp_id]);
904 if (!hwc_session_->hwc_display_[disp_id]) {
905 return -EINVAL;
906 }
907
908 hwc_session_->hwc_display_[disp_id]->GetDynamicDSIClock(bit_clk);
909
910 return 0;
911 }
912
SetDSIClk(uint32_t disp_id,uint64_t bit_clk)913 int HWCSession::DisplayConfigImpl::SetDSIClk(uint32_t disp_id, uint64_t bit_clk) {
914 SCOPE_LOCK(hwc_session_->locker_[disp_id]);
915 if (!hwc_session_->hwc_display_[disp_id]) {
916 return -1;
917 }
918
919 return hwc_session_->hwc_display_[disp_id]->SetDynamicDSIClock(bit_clk);
920 }
921
SetCWBOutputBuffer(uint32_t disp_id,const DisplayConfig::Rect rect,bool post_processed,const native_handle_t * buffer)922 int HWCSession::DisplayConfigImpl::SetCWBOutputBuffer(uint32_t disp_id,
923 const DisplayConfig::Rect rect,
924 bool post_processed,
925 const native_handle_t *buffer) {
926 if (!callback_.lock() || !buffer) {
927 DLOGE("Invalid parameters");
928 return -1;
929 }
930
931 if (disp_id != UINT32(DisplayConfig::DisplayType::kPrimary)) {
932 DLOGE("Only supported for primary display at present.");
933 return -1;
934 }
935
936 if (rect.left || rect.top || rect.right || rect.bottom) {
937 DLOGE("Cropping rectangle is not supported.");
938 return -1;
939 }
940
941 // Output buffer dump is not supported, if External or Virtual display is present.
942 int external_dpy_index = hwc_session_->GetDisplayIndex(qdutils::DISPLAY_EXTERNAL);
943 int virtual_dpy_index = hwc_session_->GetDisplayIndex(qdutils::DISPLAY_VIRTUAL);
944 int primary_dpy_index = hwc_session_->GetDisplayIndex(qdutils::DISPLAY_PRIMARY);
945
946 if (((external_dpy_index != -1) && hwc_session_->hwc_display_[external_dpy_index]) ||
947 ((virtual_dpy_index != -1) && hwc_session_->hwc_display_[virtual_dpy_index])) {
948 DLOGW("Output buffer dump is not supported with External or Virtual display!");
949 return -1;
950 }
951
952 // Mutex scope
953 {
954 SCOPE_LOCK(hwc_session_->locker_[HWC_DISPLAY_PRIMARY]);
955 if (!hwc_session_->hwc_display_[primary_dpy_index]) {
956 DLOGE("Display is not created yet.");
957 return -1;
958 }
959 }
960
961 return hwc_session_->cwb_.PostBuffer(callback_, post_processed,
962 native_handle_clone(buffer));
963 }
964
PostBuffer(std::weak_ptr<DisplayConfig::ConfigCallback> callback,bool post_processed,const native_handle_t * buffer)965 int32_t HWCSession::CWB::PostBuffer(std::weak_ptr<DisplayConfig::ConfigCallback> callback,
966 bool post_processed, const native_handle_t *buffer) {
967 SCOPE_LOCK(queue_lock_);
968
969 // Ensure that async task runs only until all queued CWB requests have been fulfilled.
970 // If cwb queue is empty, async task has not either started or async task has finished
971 // processing previously queued cwb requests. Start new async task on such a case as
972 // currently running async task will automatically desolve without processing more requests.
973 bool post_future = !queue_.size();
974
975 QueueNode *node = new QueueNode(callback, post_processed, buffer);
976 queue_.push(node);
977
978 if (post_future) {
979 // No need to do future.get() here for previously running async task. Async method will
980 // guarantee to exit after cwb for all queued requests is indeed complete i.e. the respective
981 // fences have signaled and client is notified through registered callbacks. This will make
982 // sure that the new async task does not concurrently work with previous task. Let async running
983 // thread dissolve on its own.
984 future_ = std::async(HWCSession::CWB::AsyncTask, this);
985 }
986
987 return 0;
988 }
989
ProcessRequests()990 void HWCSession::CWB::ProcessRequests() {
991 HWCDisplay *hwc_display = hwc_session_->hwc_display_[HWC_DISPLAY_PRIMARY];
992 Locker &locker = hwc_session_->locker_[HWC_DISPLAY_PRIMARY];
993
994 while (true) {
995 QueueNode *node = nullptr;
996 int status = 0;
997
998 // Mutex scope
999 // Just check if there is a next cwb request queued, exit the thread if nothing is pending.
1000 // Do not keep mutex locked so that client can freely queue more jobs to the current thread.
1001 {
1002 SCOPE_LOCK(queue_lock_);
1003 if (!queue_.size()) {
1004 break;
1005 }
1006
1007 node = queue_.front();
1008 }
1009
1010 // Configure cwb parameters, trigger refresh, wait for commit, get the release fence and
1011 // wait for fence to signal.
1012
1013 // Mutex scope
1014 // Wait for previous commit to finish before configuring next buffer.
1015 {
1016 SEQUENCE_WAIT_SCOPE_LOCK(locker);
1017 if (hwc_display->SetReadbackBuffer(node->buffer, nullptr, node->post_processed,
1018 kCWBClientExternal) != HWC2::Error::None) {
1019 DLOGE("CWB buffer could not be set.");
1020 status = -1;
1021 }
1022 }
1023
1024 if (!status) {
1025 hwc_session_->callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
1026
1027 std::unique_lock<std::mutex> lock(mutex_);
1028 cv_.wait(lock);
1029
1030 shared_ptr<Fence> release_fence = nullptr;
1031 // Mutex scope
1032 {
1033 SCOPE_LOCK(locker);
1034 hwc_display->GetReadbackBufferFence(&release_fence);
1035 }
1036
1037 if (release_fence >= 0) {
1038 status = Fence::Wait(release_fence);
1039 } else {
1040 DLOGE("CWB release fence could not be retrieved.");
1041 status = -1;
1042 }
1043 }
1044
1045 // Notify client about buffer status and erase the node from pending request queue.
1046 std::shared_ptr<DisplayConfig::ConfigCallback> callback = node->callback.lock();
1047 if (callback) {
1048 callback->NotifyCWBBufferDone(status, node->buffer);
1049 }
1050
1051 native_handle_close(node->buffer);
1052 native_handle_delete(const_cast<native_handle_t *>(node->buffer));
1053 delete node;
1054
1055 // Mutex scope
1056 // Make sure to exit here, if queue becomes empty after erasing current node from queue,
1057 // so that the current async task does not operate concurrently with a new future task.
1058 {
1059 SCOPE_LOCK(queue_lock_);
1060 queue_.pop();
1061
1062 if (!queue_.size()) {
1063 break;
1064 }
1065 }
1066 }
1067 }
1068
AsyncTask(CWB * cwb)1069 void HWCSession::CWB::AsyncTask(CWB *cwb) {
1070 cwb->ProcessRequests();
1071 }
1072
PresentDisplayDone(hwc2_display_t disp_id)1073 void HWCSession::CWB::PresentDisplayDone(hwc2_display_t disp_id) {
1074 if (disp_id != HWC_DISPLAY_PRIMARY) {
1075 return;
1076 }
1077
1078 std::unique_lock<std::mutex> lock(mutex_);
1079 cv_.notify_one();
1080 }
1081
SetQsyncMode(uint32_t disp_id,DisplayConfig::QsyncMode mode)1082 int HWCSession::DisplayConfigImpl::SetQsyncMode(uint32_t disp_id, DisplayConfig::QsyncMode mode) {
1083 SEQUENCE_WAIT_SCOPE_LOCK(hwc_session_->locker_[disp_id]);
1084 if (!hwc_session_->hwc_display_[disp_id]) {
1085 return -1;
1086 }
1087
1088 QSyncMode qsync_mode = kQSyncModeNone;
1089 switch (mode) {
1090 case DisplayConfig::QsyncMode::kNone:
1091 qsync_mode = kQSyncModeNone;
1092 break;
1093 case DisplayConfig::QsyncMode::kWaitForFencesOneFrame:
1094 qsync_mode = kQsyncModeOneShot;
1095 break;
1096 case DisplayConfig::QsyncMode::kWaitForFencesEachFrame:
1097 qsync_mode = kQsyncModeOneShotContinuous;
1098 break;
1099 case DisplayConfig::QsyncMode::kWaitForCommitEachFrame:
1100 qsync_mode = kQSyncModeContinuous;
1101 break;
1102 }
1103
1104 hwc_session_->hwc_display_[disp_id]->SetQSyncMode(qsync_mode);
1105 return 0;
1106 }
1107
IsSmartPanelConfig(uint32_t disp_id,uint32_t config_id,bool * is_smart)1108 int HWCSession::DisplayConfigImpl::IsSmartPanelConfig(uint32_t disp_id, uint32_t config_id,
1109 bool *is_smart) {
1110 if (disp_id != qdutils::DISPLAY_PRIMARY) {
1111 *is_smart = false;
1112 return -EINVAL;
1113 }
1114
1115 SCOPE_LOCK(hwc_session_->locker_[disp_id]);
1116 if (!hwc_session_->hwc_display_[disp_id]) {
1117 DLOGE("Display %d is not created yet.", disp_id);
1118 *is_smart = false;
1119 return -EINVAL;
1120 }
1121
1122 *is_smart = hwc_session_->hwc_display_[disp_id]->IsSmartPanelConfig(config_id);
1123 return 0;
1124 }
1125
IsAsyncVDSCreationSupported(bool * supported)1126 int HWCSession::DisplayConfigImpl::IsAsyncVDSCreationSupported(bool *supported) {
1127 if (!hwc_session_->async_vds_creation_) {
1128 *supported = false;
1129 return 0;
1130 }
1131
1132 *supported = true;
1133 return 0;
1134 }
1135
CreateVirtualDisplay(uint32_t width,uint32_t height,int32_t format)1136 int HWCSession::DisplayConfigImpl::CreateVirtualDisplay(uint32_t width, uint32_t height,
1137 int32_t format) {
1138 if (!hwc_session_->async_vds_creation_) {
1139 return HWC2_ERROR_UNSUPPORTED;
1140 }
1141
1142 if (!width || !height) {
1143 return HWC2_ERROR_BAD_PARAMETER;
1144 }
1145
1146 hwc2_display_t active_builtin_disp_id = hwc_session_->GetActiveBuiltinDisplay();
1147 auto status = hwc_session_->CreateVirtualDisplayObj(width, height, &format,
1148 &hwc_session_->virtual_id_);
1149 if (status == HWC2::Error::None) {
1150 DLOGI("Created virtual display id:%" PRIu64 ", res: %dx%d",
1151 hwc_session_->virtual_id_, width, height);
1152 if (active_builtin_disp_id < HWCCallbacks::kNumRealDisplays) {
1153 hwc_session_->WaitForResources(true, active_builtin_disp_id, hwc_session_->virtual_id_);
1154 }
1155 } else {
1156 DLOGE("Failed to create virtual display: %s", to_string(status).c_str());
1157 }
1158
1159 return INT(status);
1160 }
1161
IsRotatorSupportedFormat(int hal_format,bool ubwc,bool * supported)1162 int HWCSession::DisplayConfigImpl::IsRotatorSupportedFormat(int hal_format, bool ubwc,
1163 bool *supported) {
1164 if (!hwc_session_->core_intf_) {
1165 DLOGW("core_intf_ not initialized.");
1166 *supported = false;
1167 return -EINVAL;
1168 }
1169 int flag = ubwc ? private_handle_t::PRIV_FLAGS_UBWC_ALIGNED : 0;
1170
1171 LayerBufferFormat sdm_format = HWCLayer::GetSDMFormat(hal_format, flag);
1172
1173 *supported = hwc_session_->core_intf_->IsRotatorSupportedFormat(sdm_format);
1174 return 0;
1175 }
1176
ControlQsyncCallback(bool enable)1177 int HWCSession::DisplayConfigImpl::ControlQsyncCallback(bool enable) {
1178 if (enable) {
1179 hwc_session_->qsync_callback_ = callback_;
1180 } else {
1181 hwc_session_->qsync_callback_.reset();
1182 }
1183
1184 return 0;
1185 }
1186
1187 } // namespace sdm
1188