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 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 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
101
102 if (disp_id >= 0) {
103 connected = hwc_display_[disp_id];
104 error = 0;
105 }
106
107 _hidl_cb(error, connected);
108
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 < 0) {
114 return -EINVAL;
115 }
116
117 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
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 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
139 HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
140
141 switch (op) {
142 case IDisplayConfig::DisplayDynRefreshRateOp::DISABLE_METADATA_DYN_REFRESH_RATE:
143 return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
144
145 case IDisplayConfig::DisplayDynRefreshRateOp::ENABLE_METADATA_DYN_REFRESH_RATE:
146 return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true);
147
148 case IDisplayConfig::DisplayDynRefreshRateOp::SET_BINDER_DYN_REFRESH_RATE:
149 return hwc_display->Perform(HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE, refreshRate);
150
151 default:
152 DLOGW("Invalid operation %d", op);
153 return -EINVAL;
154 }
155
156 return 0;
157 }
158
GetConfigCount(int disp_id,uint32_t * count)159 int32_t HWCSession::GetConfigCount(int disp_id, uint32_t *count) {
160 if (disp_id < 0) {
161 return -EINVAL;
162 }
163
164 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
165
166 if (hwc_display_[disp_id]) {
167 return hwc_display_[disp_id]->GetDisplayConfigCount(count);
168 }
169
170 return -EINVAL;
171 }
172
getConfigCount(IDisplayConfig::DisplayType dpy,getConfigCount_cb _hidl_cb)173 Return<void> HWCSession::getConfigCount(IDisplayConfig::DisplayType dpy,
174 getConfigCount_cb _hidl_cb) {
175 uint32_t count = 0;
176 int32_t error = GetConfigCount(MapDisplayType(dpy), &count);
177
178 _hidl_cb(error, count);
179
180 return Void();
181 }
182
GetActiveConfigIndex(int disp_id,uint32_t * config)183 int32_t HWCSession::GetActiveConfigIndex(int disp_id, uint32_t *config) {
184 if (disp_id < 0) {
185 return -EINVAL;
186 }
187
188 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
189
190 if (hwc_display_[disp_id]) {
191 return hwc_display_[disp_id]->GetActiveDisplayConfig(config);
192 }
193
194 return -EINVAL;
195 }
196
getActiveConfig(IDisplayConfig::DisplayType dpy,getActiveConfig_cb _hidl_cb)197 Return<void> HWCSession::getActiveConfig(IDisplayConfig::DisplayType dpy,
198 getActiveConfig_cb _hidl_cb) {
199 uint32_t config = 0;
200 int32_t error = GetActiveConfigIndex(MapDisplayType(dpy), &config);
201
202 _hidl_cb(error, config);
203
204 return Void();
205 }
206
SetActiveConfigIndex(int disp_id,uint32_t config)207 int32_t HWCSession::SetActiveConfigIndex(int disp_id, uint32_t config) {
208 if (disp_id < 0) {
209 return -EINVAL;
210 }
211
212 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
213 int32_t error = -EINVAL;
214 if (hwc_display_[disp_id]) {
215 error = hwc_display_[disp_id]->SetActiveDisplayConfig(config);
216 if (!error) {
217 Refresh(0);
218 }
219 }
220
221 return error;
222 }
223
setActiveConfig(IDisplayConfig::DisplayType dpy,uint32_t config)224 Return<int32_t> HWCSession::setActiveConfig(IDisplayConfig::DisplayType dpy, uint32_t config) {
225 return SetActiveConfigIndex(MapDisplayType(dpy), config);
226 }
227
getDisplayAttributes(uint32_t configIndex,IDisplayConfig::DisplayType dpy,getDisplayAttributes_cb _hidl_cb)228 Return<void> HWCSession::getDisplayAttributes(uint32_t configIndex,
229 IDisplayConfig::DisplayType dpy,
230 getDisplayAttributes_cb _hidl_cb) {
231 int32_t error = -EINVAL;
232 IDisplayConfig::DisplayAttributes display_attributes = {};
233 int disp_id = MapDisplayType(dpy);
234
235 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
236 if (disp_id >= 0 && hwc_display_[disp_id]) {
237 DisplayConfigVariableInfo hwc_display_attributes;
238 error = hwc_display_[disp_id]->GetDisplayAttributesForConfig(static_cast<int>(configIndex),
239 &hwc_display_attributes);
240 if (!error) {
241 display_attributes.vsyncPeriod = hwc_display_attributes.vsync_period_ns;
242 display_attributes.xRes = hwc_display_attributes.x_pixels;
243 display_attributes.yRes = hwc_display_attributes.y_pixels;
244 display_attributes.xDpi = hwc_display_attributes.x_dpi;
245 display_attributes.yDpi = hwc_display_attributes.y_dpi;
246 display_attributes.panelType = IDisplayConfig::DisplayPortType::DISPLAY_PORT_DEFAULT;
247 display_attributes.isYuv = hwc_display_attributes.is_yuv;
248 }
249 }
250
251 return Void();
252 }
253
setPanelBrightness(uint32_t level)254 Return<int32_t> HWCSession::setPanelBrightness(uint32_t level) {
255 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
256 int32_t error = -EINVAL;
257
258 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
259 error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(static_cast<int>(level));
260 if (error) {
261 DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error);
262 }
263 }
264
265 return error;
266 }
267
GetPanelBrightness(int * level)268 int32_t HWCSession::GetPanelBrightness(int *level) {
269 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
270 int32_t error = -EINVAL;
271
272 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
273 error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(level);
274 if (error) {
275 DLOGE("Failed to get the panel brightness. Error = %d", error);
276 }
277 }
278
279 return error;
280 }
281
getPanelBrightness(getPanelBrightness_cb _hidl_cb)282 Return<void> HWCSession::getPanelBrightness(getPanelBrightness_cb _hidl_cb) {
283 int level = 0;
284 int32_t error = GetPanelBrightness(&level);
285
286 _hidl_cb(error, static_cast<uint32_t>(level));
287
288 return Void();
289 }
290
MinHdcpEncryptionLevelChanged(int disp_id,uint32_t min_enc_level)291 int32_t HWCSession::MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level) {
292 DLOGI("Display %d", disp_id);
293
294 if (disp_id < 0) {
295 return -EINVAL;
296 }
297
298 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
299 if (disp_id != HWC_DISPLAY_EXTERNAL) {
300 DLOGE("Not supported for display");
301 } else if (!hwc_display_[disp_id]) {
302 DLOGW("Display is not connected");
303 } else {
304 return hwc_display_[disp_id]->OnMinHdcpEncryptionLevelChange(min_enc_level);
305 }
306
307 return -EINVAL;
308 }
309
minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,uint32_t min_enc_level)310 Return<int32_t> HWCSession::minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,
311 uint32_t min_enc_level) {
312 return MinHdcpEncryptionLevelChanged(MapDisplayType(dpy), min_enc_level);
313 }
314
refreshScreen()315 Return<int32_t> HWCSession::refreshScreen() {
316 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
317 Refresh(HWC_DISPLAY_PRIMARY);
318
319 return 0;
320 }
321
ControlPartialUpdate(int disp_id,bool enable)322 int32_t HWCSession::ControlPartialUpdate(int disp_id, bool enable) {
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 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
333 HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
334 if (!hwc_display) {
335 DLOGE("primary display object is not instantiated");
336 return -EINVAL;
337 }
338
339 uint32_t pending = 0;
340 DisplayError hwc_error = hwc_display->ControlPartialUpdate(enable, &pending);
341
342 if (hwc_error == kErrorNone) {
343 if (!pending) {
344 return 0;
345 }
346 } else if (hwc_error == kErrorNotSupported) {
347 return 0;
348 } else {
349 return -EINVAL;
350 }
351
352 // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future.
353 Refresh(HWC_DISPLAY_PRIMARY);
354
355 // Wait until partial update control is complete
356 int32_t error = locker_[disp_id].WaitFinite(kPartialUpdateControlTimeoutMs);
357
358 return error;
359 }
360
controlPartialUpdate(IDisplayConfig::DisplayType dpy,bool enable)361 Return<int32_t> HWCSession::controlPartialUpdate(IDisplayConfig::DisplayType dpy, bool enable) {
362 return ControlPartialUpdate(MapDisplayType(dpy), enable);
363 }
364
toggleScreenUpdate(bool on)365 Return<int32_t> HWCSession::toggleScreenUpdate(bool on) {
366 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
367
368 int32_t error = -EINVAL;
369 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
370 error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(on);
371 if (error) {
372 DLOGE("Failed to toggle screen updates = %d. Error = %d", on, error);
373 }
374 }
375
376 return error;
377 }
378
setIdleTimeout(uint32_t value)379 Return<int32_t> HWCSession::setIdleTimeout(uint32_t value) {
380 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
381
382 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
383 hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(value);
384 return 0;
385 }
386
387 return -EINVAL;
388 }
389
getHDRCapabilities(IDisplayConfig::DisplayType dpy,getHDRCapabilities_cb _hidl_cb)390 Return<void> HWCSession::getHDRCapabilities(IDisplayConfig::DisplayType dpy,
391 getHDRCapabilities_cb _hidl_cb) {
392 int32_t error = -EINVAL;
393 IDisplayConfig::DisplayHDRCapabilities hdr_caps = {};
394
395 do {
396 int disp_id = MapDisplayType(dpy);
397 if (disp_id < 0) {
398 DLOGE("Invalid display id = %d", disp_id);
399 break;
400 }
401
402 SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
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 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
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 SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
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 #ifdef DISPLAY_CONFIG_1_1
485 // Methods from ::vendor::hardware::display::config::V1_1::IDisplayConfig follow.
setDisplayAnimating(uint64_t display_id,bool animating)486 Return<int32_t> HWCSession::setDisplayAnimating(uint64_t display_id, bool animating ) {
487 SEQUENCE_WAIT_SCOPE_LOCK(locker_[display_id]);
488 return CallDisplayFunction(static_cast<hwc2_device_t *>(this), display_id,
489 &HWCDisplay::SetDisplayAnimating, animating);
490 }
491 #endif
492
493
494 } // namespace sdm
495