1 /*
2 * Copyright (c) 2017-2018, 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 ALOGW("%s::%s: Could not register IDisplayConfig as service (%d).",
48 __CLASS__, __FUNCTION__, status);
49 } else {
50 ALOGI("%s::%s: IDisplayConfig service registration completed.", __CLASS__, __FUNCTION__);
51 }
52 }
53
MapDisplayType(IDisplayConfig::DisplayType dpy)54 int MapDisplayType(IDisplayConfig::DisplayType dpy) {
55 switch (dpy) {
56 case IDisplayConfig::DisplayType::DISPLAY_PRIMARY:
57 return HWC_DISPLAY_PRIMARY;
58
59 case IDisplayConfig::DisplayType::DISPLAY_EXTERNAL:
60 return HWC_DISPLAY_EXTERNAL;
61
62 case IDisplayConfig::DisplayType::DISPLAY_VIRTUAL:
63 return HWC_DISPLAY_VIRTUAL;
64
65 default:
66 break;
67 }
68
69 return -EINVAL;
70 }
71
MapExternalStatus(IDisplayConfig::DisplayExternalStatus status)72 HWCDisplay::DisplayStatus MapExternalStatus(IDisplayConfig::DisplayExternalStatus status) {
73 switch (status) {
74 case IDisplayConfig::DisplayExternalStatus::EXTERNAL_OFFLINE:
75 return HWCDisplay::kDisplayStatusOffline;
76
77 case IDisplayConfig::DisplayExternalStatus::EXTERNAL_ONLINE:
78 return HWCDisplay::kDisplayStatusOnline;
79
80 case IDisplayConfig::DisplayExternalStatus::EXTERNAL_PAUSE:
81 return HWCDisplay::kDisplayStatusPause;
82
83 case IDisplayConfig::DisplayExternalStatus::EXTERNAL_RESUME:
84 return HWCDisplay::kDisplayStatusResume;
85
86 default:
87 break;
88 }
89
90 return HWCDisplay::kDisplayStatusInvalid;
91 }
92
93 // Methods from ::vendor::hardware::display::config::V1_0::IDisplayConfig follow.
isDisplayConnected(IDisplayConfig::DisplayType dpy,isDisplayConnected_cb _hidl_cb)94 Return<void> HWCSession::isDisplayConnected(IDisplayConfig::DisplayType dpy,
95 isDisplayConnected_cb _hidl_cb) {
96 int32_t error = -EINVAL;
97 bool connected = false;
98
99 int disp_id = MapDisplayType(dpy);
100
101 if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
102 _hidl_cb(error, connected);
103 return Void();
104 }
105
106 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
107
108 if (disp_id >= 0) {
109 connected = hwc_display_[disp_id];
110 error = 0;
111 }
112
113 _hidl_cb(error, connected);
114
115 return Void();
116 }
117
SetSecondaryDisplayStatus(int disp_id,HWCDisplay::DisplayStatus status)118 int32_t HWCSession::SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status) {
119 if (disp_id < 0) {
120 return -EINVAL;
121 }
122
123 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
124 DLOGI("Display = %d, Status = %d", disp_id, status);
125
126 if (disp_id == HWC_DISPLAY_PRIMARY) {
127 DLOGE("Not supported for this display");
128 } else if (!hwc_display_[disp_id]) {
129 DLOGW("Display is not connected");
130 } else {
131 return hwc_display_[disp_id]->SetDisplayStatus(status);
132 }
133
134 return -EINVAL;
135 }
136
setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy,IDisplayConfig::DisplayExternalStatus status)137 Return<int32_t> HWCSession::setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy,
138 IDisplayConfig::DisplayExternalStatus status) {
139 return SetSecondaryDisplayStatus(MapDisplayType(dpy), MapExternalStatus(status));
140 }
141
configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op,uint32_t refreshRate)142 Return<int32_t> HWCSession::configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op,
143 uint32_t refreshRate) {
144 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
145 HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
146
147 switch (op) {
148 case IDisplayConfig::DisplayDynRefreshRateOp::DISABLE_METADATA_DYN_REFRESH_RATE:
149 return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
150
151 case IDisplayConfig::DisplayDynRefreshRateOp::ENABLE_METADATA_DYN_REFRESH_RATE:
152 return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true);
153
154 case IDisplayConfig::DisplayDynRefreshRateOp::SET_BINDER_DYN_REFRESH_RATE:
155 return hwc_display->Perform(HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE, refreshRate);
156
157 default:
158 DLOGW("Invalid operation %d", op);
159 return -EINVAL;
160 }
161
162 return 0;
163 }
164
GetConfigCount(int disp_id,uint32_t * count)165 int32_t HWCSession::GetConfigCount(int disp_id, uint32_t *count) {
166 if (disp_id < 0) {
167 return -EINVAL;
168 }
169
170 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
171
172 if (hwc_display_[disp_id]) {
173 return hwc_display_[disp_id]->GetDisplayConfigCount(count);
174 }
175
176 return -EINVAL;
177 }
178
getConfigCount(IDisplayConfig::DisplayType dpy,getConfigCount_cb _hidl_cb)179 Return<void> HWCSession::getConfigCount(IDisplayConfig::DisplayType dpy,
180 getConfigCount_cb _hidl_cb) {
181 uint32_t count = 0;
182 int32_t error = GetConfigCount(MapDisplayType(dpy), &count);
183
184 _hidl_cb(error, count);
185
186 return Void();
187 }
188
GetActiveConfigIndex(int disp_id,uint32_t * config)189 int32_t HWCSession::GetActiveConfigIndex(int disp_id, uint32_t *config) {
190 if (disp_id < 0) {
191 return -EINVAL;
192 }
193
194 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
195
196 if (hwc_display_[disp_id]) {
197 return hwc_display_[disp_id]->GetActiveDisplayConfig(config);
198 }
199
200 return -EINVAL;
201 }
202
getActiveConfig(IDisplayConfig::DisplayType dpy,getActiveConfig_cb _hidl_cb)203 Return<void> HWCSession::getActiveConfig(IDisplayConfig::DisplayType dpy,
204 getActiveConfig_cb _hidl_cb) {
205 uint32_t config = 0;
206 int32_t error = GetActiveConfigIndex(MapDisplayType(dpy), &config);
207
208 _hidl_cb(error, config);
209
210 return Void();
211 }
212
SetActiveConfigIndex(int disp_id,uint32_t config)213 int32_t HWCSession::SetActiveConfigIndex(int disp_id, uint32_t config) {
214 if (disp_id < 0) {
215 return -EINVAL;
216 }
217
218 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
219 int32_t error = -EINVAL;
220 if (hwc_display_[disp_id]) {
221 error = hwc_display_[disp_id]->SetActiveDisplayConfig(config);
222 if (!error) {
223 Refresh(0);
224 }
225 }
226
227 return error;
228 }
229
setActiveConfig(IDisplayConfig::DisplayType dpy,uint32_t config)230 Return<int32_t> HWCSession::setActiveConfig(IDisplayConfig::DisplayType dpy, uint32_t config) {
231 return SetActiveConfigIndex(MapDisplayType(dpy), config);
232 }
233
getDisplayAttributes(uint32_t configIndex,IDisplayConfig::DisplayType dpy,getDisplayAttributes_cb _hidl_cb)234 Return<void> HWCSession::getDisplayAttributes(uint32_t configIndex,
235 IDisplayConfig::DisplayType dpy,
236 getDisplayAttributes_cb _hidl_cb) {
237 int32_t error = -EINVAL;
238 IDisplayConfig::DisplayAttributes display_attributes = {};
239 int disp_id = MapDisplayType(dpy);
240
241 if (disp_id >= HWC_DISPLAY_PRIMARY && disp_id < HWC_NUM_DISPLAY_TYPES) {
242 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
243 if (hwc_display_[disp_id]) {
244 DisplayConfigVariableInfo hwc_display_attributes;
245 error = hwc_display_[disp_id]->GetDisplayAttributesForConfig(static_cast<int>(configIndex),
246 &hwc_display_attributes);
247 if (!error) {
248 display_attributes.vsyncPeriod = hwc_display_attributes.vsync_period_ns;
249 display_attributes.xRes = hwc_display_attributes.x_pixels;
250 display_attributes.yRes = hwc_display_attributes.y_pixels;
251 display_attributes.xDpi = hwc_display_attributes.x_dpi;
252 display_attributes.yDpi = hwc_display_attributes.y_dpi;
253 display_attributes.panelType = IDisplayConfig::DisplayPortType::DISPLAY_PORT_DEFAULT;
254 display_attributes.isYuv = hwc_display_attributes.is_yuv;
255 }
256 }
257 }
258 _hidl_cb(error, display_attributes);
259
260 return Void();
261 }
262
setPanelBrightness(uint32_t level)263 Return<int32_t> HWCSession::setPanelBrightness(uint32_t level) {
264 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
265 int32_t error = -EINVAL;
266
267 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
268 error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(static_cast<int>(level));
269 if (error) {
270 DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error);
271 }
272 }
273
274 return error;
275 }
276
GetPanelBrightness(int * level)277 int32_t HWCSession::GetPanelBrightness(int *level) {
278 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
279 int32_t error = -EINVAL;
280
281 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
282 error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(level);
283 if (error) {
284 DLOGE("Failed to get the panel brightness. Error = %d", error);
285 }
286 }
287
288 return error;
289 }
290
getPanelBrightness(getPanelBrightness_cb _hidl_cb)291 Return<void> HWCSession::getPanelBrightness(getPanelBrightness_cb _hidl_cb) {
292 int level = 0;
293 int32_t error = GetPanelBrightness(&level);
294
295 _hidl_cb(error, static_cast<uint32_t>(level));
296
297 return Void();
298 }
299
MinHdcpEncryptionLevelChanged(int disp_id,uint32_t min_enc_level)300 int32_t HWCSession::MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level) {
301 DLOGI("Display %d", disp_id);
302
303 if (disp_id < 0) {
304 return -EINVAL;
305 }
306
307 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
308 if (disp_id != HWC_DISPLAY_EXTERNAL) {
309 DLOGE("Not supported for display");
310 } else if (!hwc_display_[disp_id]) {
311 DLOGW("Display is not connected");
312 } else {
313 return hwc_display_[disp_id]->OnMinHdcpEncryptionLevelChange(min_enc_level);
314 }
315
316 return -EINVAL;
317 }
318
minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,uint32_t min_enc_level)319 Return<int32_t> HWCSession::minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,
320 uint32_t min_enc_level) {
321 return MinHdcpEncryptionLevelChanged(MapDisplayType(dpy), min_enc_level);
322 }
323
refreshScreen()324 Return<int32_t> HWCSession::refreshScreen() {
325 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
326 Refresh(HWC_DISPLAY_PRIMARY);
327
328 return 0;
329 }
330
ControlPartialUpdate(int disp_id,bool enable)331 int32_t HWCSession::ControlPartialUpdate(int disp_id, bool enable) {
332 if (disp_id < 0) {
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(kPartialUpdateControlTimeoutMs);
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 return -EINVAL;
397 }
398
getHDRCapabilities(IDisplayConfig::DisplayType dpy,getHDRCapabilities_cb _hidl_cb)399 Return<void> HWCSession::getHDRCapabilities(IDisplayConfig::DisplayType dpy,
400 getHDRCapabilities_cb _hidl_cb) {
401 int32_t error = -EINVAL;
402 IDisplayConfig::DisplayHDRCapabilities hdr_caps = {};
403
404 do {
405 int disp_id = MapDisplayType(dpy);
406 if ((disp_id < 0) || (disp_id >= HWC_NUM_DISPLAY_TYPES)) {
407 DLOGE("Invalid display id = %d", disp_id);
408 break;
409 }
410
411 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
412 HWCDisplay *hwc_display = hwc_display_[disp_id];
413 if (!hwc_display) {
414 DLOGE("Display = %d is not connected.", disp_id);
415 break;
416 }
417
418 // query number of hdr types
419 uint32_t out_num_types = 0;
420 if (hwc_display->GetHdrCapabilities(&out_num_types, nullptr, nullptr, nullptr, nullptr)
421 != HWC2::Error::None) {
422 break;
423 }
424
425 if (!out_num_types) {
426 error = 0;
427 break;
428 }
429
430 // query hdr caps
431 hdr_caps.supportedHdrTypes.resize(out_num_types);
432
433 float out_max_luminance = 0.0f;
434 float out_max_average_luminance = 0.0f;
435 float out_min_luminance = 0.0f;
436 if (hwc_display->GetHdrCapabilities(&out_num_types, hdr_caps.supportedHdrTypes.data(),
437 &out_max_luminance, &out_max_average_luminance,
438 &out_min_luminance)
439 == HWC2::Error::None) {
440 error = 0;
441 }
442 } while (false);
443
444 _hidl_cb(error, hdr_caps);
445
446 return Void();
447 }
448
setCameraLaunchStatus(uint32_t on)449 Return<int32_t> HWCSession::setCameraLaunchStatus(uint32_t on) {
450 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
451
452 HWBwModes mode = on > 0 ? kBwCamera : kBwDefault;
453
454 // trigger invalidate to apply new bw caps.
455 Refresh(HWC_DISPLAY_PRIMARY);
456
457 if (core_intf_->SetMaxBandwidthMode(mode) != kErrorNone) {
458 return -EINVAL;
459 }
460
461 new_bw_mode_ = true;
462 need_invalidate_ = true;
463 hwc_display_[HWC_DISPLAY_PRIMARY]->ResetValidation();
464
465 return 0;
466 }
467
DisplayBWTransactionPending(bool * status)468 int32_t HWCSession::DisplayBWTransactionPending(bool *status) {
469 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
470
471 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
472 if (sync_wait(bw_mode_release_fd_, 0) < 0) {
473 DLOGI("bw_transaction_release_fd is not yet signaled: err= %s", strerror(errno));
474 *status = false;
475 }
476
477 return 0;
478 }
479
480 return -EINVAL;
481 }
482
displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb)483 Return<void> HWCSession::displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb) {
484 bool status = true;
485
486 int32_t error = DisplayBWTransactionPending(&status);
487
488 _hidl_cb(error, status);
489
490 return Void();
491 }
492
493 #ifdef DISPLAY_CONFIG_1_1
494 // Methods from ::vendor::hardware::display::config::V1_1::IDisplayConfig follow.
setDisplayAnimating(uint64_t display_id,bool animating)495 Return<int32_t> HWCSession::setDisplayAnimating(uint64_t display_id, bool animating ) {
496 SEQUENCE_WAIT_SCOPE_LOCK(locker_[display_id]);
497 return CallDisplayFunction(static_cast<hwc2_device_t *>(this), display_id,
498 &HWCDisplay::SetDisplayAnimating, animating);
499 }
500 #endif
501
502
503 } // namespace sdm
504