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