1 /*
2 * Copyright (c) 2014 - 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/dump_interface.h>
31 #include <core/buffer_allocator.h>
32 #include <private/color_params.h>
33 #include <utils/constants.h>
34 #include <utils/String16.h>
35 #include <cutils/properties.h>
36 #include <hardware_legacy/uevent.h>
37 #include <sys/resource.h>
38 #include <sys/prctl.h>
39 #include <binder/Parcel.h>
40 #include <QService.h>
41 #include <gr.h>
42 #include <gralloc_priv.h>
43 #include <display_config.h>
44 #include <utils/debug.h>
45 #include <sync/sync.h>
46 #include <profiler.h>
47 #include <bitset>
48 #include <vector>
49
50 #include "hwc_buffer_allocator.h"
51 #include "hwc_buffer_sync_handler.h"
52 #include "hwc_session.h"
53 #include "hwc_debugger.h"
54 #include "hwc_display_null.h"
55 #include "hwc_display_primary.h"
56 #include "hwc_display_virtual.h"
57 #include "hwc_display_external_test.h"
58 #include "qd_utils.h"
59
60 #define __CLASS__ "HWCSession"
61
62 #define HWC_UEVENT_SWITCH_HDMI "change@/devices/virtual/switch/hdmi"
63 #define HWC_UEVENT_GRAPHICS_FB0 "change@/devices/virtual/graphics/fb0"
64
65 static sdm::HWCSession::HWCModuleMethods g_hwc_module_methods;
66
67 hwc_module_t HAL_MODULE_INFO_SYM = {
68 .common = {
69 .tag = HARDWARE_MODULE_TAG,
70 .version_major = 2,
71 .version_minor = 0,
72 .id = HWC_HARDWARE_MODULE_ID,
73 .name = "QTI Hardware Composer Module",
74 .author = "CodeAurora Forum",
75 .methods = &g_hwc_module_methods,
76 .dso = 0,
77 .reserved = {0},
78 }
79 };
80
81 namespace sdm {
82
83 Locker HWCSession::locker_;
84
Invalidate(const struct hwc_procs * procs)85 static void Invalidate(const struct hwc_procs *procs) {
86 }
87
VSync(const struct hwc_procs * procs,int disp,int64_t timestamp)88 static void VSync(const struct hwc_procs* procs, int disp, int64_t timestamp) {
89 }
90
Hotplug(const struct hwc_procs * procs,int disp,int connected)91 static void Hotplug(const struct hwc_procs* procs, int disp, int connected) {
92 }
93
HWCSession(const hw_module_t * module)94 HWCSession::HWCSession(const hw_module_t *module) {
95 // By default, drop any events. Calls will be routed to SurfaceFlinger after registerProcs.
96 hwc_procs_default_.invalidate = Invalidate;
97 hwc_procs_default_.vsync = VSync;
98 hwc_procs_default_.hotplug = Hotplug;
99
100 hwc_composer_device_1_t::common.tag = HARDWARE_DEVICE_TAG;
101 hwc_composer_device_1_t::common.version = HWC_DEVICE_API_VERSION_1_5;
102 hwc_composer_device_1_t::common.module = const_cast<hw_module_t*>(module);
103 hwc_composer_device_1_t::common.close = Close;
104 hwc_composer_device_1_t::prepare = Prepare;
105 hwc_composer_device_1_t::set = Set;
106 hwc_composer_device_1_t::eventControl = EventControl;
107 hwc_composer_device_1_t::setPowerMode = SetPowerMode;
108 hwc_composer_device_1_t::query = Query;
109 hwc_composer_device_1_t::registerProcs = RegisterProcs;
110 hwc_composer_device_1_t::dump = Dump;
111 hwc_composer_device_1_t::getDisplayConfigs = GetDisplayConfigs;
112 hwc_composer_device_1_t::getDisplayAttributes = GetDisplayAttributes;
113 hwc_composer_device_1_t::getActiveConfig = GetActiveConfig;
114 hwc_composer_device_1_t::setActiveConfig = SetActiveConfig;
115 hwc_composer_device_1_t::setCursorPositionAsync = SetCursorPositionAsync;
116 }
117
Init()118 int HWCSession::Init() {
119 int status = -EINVAL;
120 const char *qservice_name = "display.qservice";
121
122 // Start QService and connect to it.
123 qService::QService::init();
124 android::sp<qService::IQService> iqservice = android::interface_cast<qService::IQService>(
125 android::defaultServiceManager()->getService(android::String16(qservice_name)));
126
127 if (iqservice.get()) {
128 iqservice->connect(android::sp<qClient::IQClient>(this));
129 qservice_ = reinterpret_cast<qService::QService* >(iqservice.get());
130 } else {
131 DLOGE("Failed to acquire %s", qservice_name);
132 return -EINVAL;
133 }
134
135 DisplayError error = CoreInterface::CreateCore(HWCDebugHandler::Get(), &buffer_allocator_,
136 &buffer_sync_handler_, &socket_handler_,
137 &core_intf_);
138 if (error != kErrorNone) {
139 DLOGE("Display core initialization failed. Error = %d", error);
140 return -EINVAL;
141 }
142
143 SCOPE_LOCK(uevent_locker_);
144
145 if (pthread_create(&uevent_thread_, NULL, &HWCUeventThread, this) < 0) {
146 DLOGE("Failed to start = %s, error = %s", uevent_thread_name_, strerror(errno));
147 CoreInterface::DestroyCore();
148 return -errno;
149 }
150
151 // Wait for uevent_init() to happen and let the uevent thread wait for uevents, so that hdmi
152 // connect/disconnect events won't be missed
153 uevent_locker_.Wait();
154
155 // Read which display is first, and create it and store it in primary slot
156 HWDisplayInterfaceInfo hw_disp_info;
157 error = core_intf_->GetFirstDisplayInterfaceType(&hw_disp_info);
158 if (error == kErrorNone) {
159 if (hw_disp_info.type == kHDMI) {
160 // HDMI is primary display. If already connected, then create it and store in
161 // primary display slot. If not connected, create a NULL display for now.
162 HWCDebugHandler::Get()->SetProperty("persist.sys.is_hdmi_primary", "1");
163 is_hdmi_primary_ = true;
164 if (hw_disp_info.is_connected) {
165 status = CreateExternalDisplay(HWC_DISPLAY_PRIMARY, 0, 0, false);
166 is_hdmi_yuv_ = IsDisplayYUV(HWC_DISPLAY_PRIMARY);
167 } else {
168 // NullDisplay simply closes all its fences, and advertizes a standard
169 // resolution to SurfaceFlinger
170 status = HWCDisplayNull::Create(core_intf_, &hwc_procs_,
171 &hwc_display_[HWC_DISPLAY_PRIMARY]);
172 }
173 } else {
174 // Create and power on primary display
175 status = HWCDisplayPrimary::Create(core_intf_, &buffer_allocator_, &hwc_procs_, qservice_,
176 &hwc_display_[HWC_DISPLAY_PRIMARY]);
177 }
178 } else {
179 // Create and power on primary display
180 status = HWCDisplayPrimary::Create(core_intf_, &buffer_allocator_, &hwc_procs_, qservice_,
181 &hwc_display_[HWC_DISPLAY_PRIMARY]);
182 }
183
184 if (status) {
185 CoreInterface::DestroyCore();
186 uevent_thread_exit_ = true;
187 pthread_join(uevent_thread_, NULL);
188 return status;
189 }
190
191 color_mgr_ = HWCColorManager::CreateColorManager();
192 if (!color_mgr_) {
193 DLOGW("Failed to load HWCColorManager.");
194 }
195
196 connected_displays_[HWC_DISPLAY_PRIMARY] = 1;
197 struct rlimit fd_limit = {};
198 getrlimit(RLIMIT_NOFILE, &fd_limit);
199 fd_limit.rlim_cur = fd_limit.rlim_cur * 2;
200 auto err = setrlimit(RLIMIT_NOFILE, &fd_limit);
201 if (err) {
202 DLOGW("Unable to increase fd limit - err: %d, %s", errno, strerror(errno));
203 }
204 return 0;
205 }
206
Deinit()207 int HWCSession::Deinit() {
208 HWCDisplayPrimary::Destroy(hwc_display_[HWC_DISPLAY_PRIMARY]);
209 hwc_display_[HWC_DISPLAY_PRIMARY] = 0;
210 if (color_mgr_) {
211 color_mgr_->DestroyColorManager();
212 }
213 uevent_thread_exit_ = true;
214 pthread_join(uevent_thread_, NULL);
215
216 DisplayError error = CoreInterface::DestroyCore();
217 if (error != kErrorNone) {
218 DLOGE("Display core de-initialization failed. Error = %d", error);
219 }
220
221 connected_displays_[HWC_DISPLAY_PRIMARY] = 0;
222 return 0;
223 }
224
Open(const hw_module_t * module,const char * name,hw_device_t ** device)225 int HWCSession::Open(const hw_module_t *module, const char *name, hw_device_t **device) {
226 SEQUENCE_WAIT_SCOPE_LOCK(locker_);
227
228 if (!module || !name || !device) {
229 DLOGE("Invalid parameters.");
230 return -EINVAL;
231 }
232
233 if (!strcmp(name, HWC_HARDWARE_COMPOSER)) {
234 HWCSession *hwc_session = new HWCSession(module);
235 if (!hwc_session) {
236 return -ENOMEM;
237 }
238
239 int status = hwc_session->Init();
240 if (status != 0) {
241 delete hwc_session;
242 return status;
243 }
244
245 hwc_composer_device_1_t *composer_device = hwc_session;
246 *device = reinterpret_cast<hw_device_t *>(composer_device);
247 }
248
249 return 0;
250 }
251
Close(hw_device_t * device)252 int HWCSession::Close(hw_device_t *device) {
253 SEQUENCE_WAIT_SCOPE_LOCK(locker_);
254
255 if (!device) {
256 return -EINVAL;
257 }
258
259 hwc_composer_device_1_t *composer_device = reinterpret_cast<hwc_composer_device_1_t *>(device);
260 HWCSession *hwc_session = static_cast<HWCSession *>(composer_device);
261
262 hwc_session->Deinit();
263 delete hwc_session;
264
265 return 0;
266 }
267
Prepare(hwc_composer_device_1 * device,size_t num_displays,hwc_display_contents_1_t ** displays)268 int HWCSession::Prepare(hwc_composer_device_1 *device, size_t num_displays,
269 hwc_display_contents_1_t **displays) {
270 DTRACE_SCOPED();
271
272 if (!device || !displays || num_displays > HWC_NUM_DISPLAY_TYPES) {
273 return -EINVAL;
274 }
275
276 HWCSession *hwc_session = static_cast<HWCSession *>(device);
277 hwc_procs_t const *hwc_procs = NULL;
278 bool hotplug_connect = false;
279
280 // Hold mutex only in this scope.
281 {
282 SEQUENCE_ENTRY_SCOPE_LOCK(locker_);
283
284 hwc_procs = hwc_session->hwc_procs_;
285
286 if (hwc_session->reset_panel_) {
287 DLOGW("panel is in bad state, resetting the panel");
288 hwc_session->ResetPanel();
289 }
290
291 if (hwc_session->need_invalidate_) {
292 hwc_procs->invalidate(hwc_procs);
293 hwc_session->need_invalidate_ = false;
294 }
295
296 hwc_session->HandleSecureDisplaySession(displays);
297
298 if (hwc_session->color_mgr_) {
299 HWCDisplay *primary_display = hwc_session->hwc_display_[HWC_DISPLAY_PRIMARY];
300 if (primary_display && !hwc_session->is_hdmi_primary_) {
301 int ret = hwc_session->color_mgr_->SolidFillLayersPrepare(displays, primary_display);
302 if (ret)
303 return 0;
304 }
305 }
306
307 for (ssize_t dpy = static_cast<ssize_t>(num_displays - 1); dpy >= 0; dpy--) {
308 hwc_display_contents_1_t *content_list = displays[dpy];
309 // If external display is connected, ignore virtual display content list.
310 // If virtual display content list is valid, connect virtual display if not connected.
311 // If virtual display content list is invalid, disconnect virtual display if connected.
312 // If external display connection is pending, connect external display when virtual
313 // display is destroyed.
314 // If HDMI is primary and the output format is YUV then ignore the virtual display
315 // content list.
316 if (dpy == HWC_DISPLAY_VIRTUAL) {
317 if (hwc_session->hwc_display_[HWC_DISPLAY_EXTERNAL] ||
318 (hwc_session->is_hdmi_primary_ && hwc_session->is_hdmi_yuv_)) {
319 continue;
320 }
321
322 bool valid_content = HWCDisplayVirtual::IsValidContentList(content_list);
323 bool connected = (hwc_session->hwc_display_[HWC_DISPLAY_VIRTUAL] != NULL);
324
325 if (valid_content && !connected) {
326 hwc_session->ConnectDisplay(HWC_DISPLAY_VIRTUAL, content_list);
327 } else if (!valid_content && connected) {
328 hwc_session->DisconnectDisplay(HWC_DISPLAY_VIRTUAL);
329
330 if (hwc_session->external_pending_connect_) {
331 DLOGI("Process pending external display connection");
332 hwc_session->ConnectDisplay(HWC_DISPLAY_EXTERNAL, NULL);
333 hwc_session->external_pending_connect_ = false;
334 hotplug_connect = true;
335 }
336 }
337 }
338
339 if (hwc_session->hwc_display_[dpy]) {
340 if (!content_list) {
341 DLOGI("Display[%d] connected. content_list is null", dpy);
342 } else if (!content_list->numHwLayers) {
343 DLOGE("Display[%d] connected. numHwLayers is zero", dpy);
344 } else {
345 hwc_session->hwc_display_[dpy]->Prepare(content_list);
346 }
347 }
348 }
349 }
350
351 if (hotplug_connect) {
352 // notify client
353 hwc_procs->hotplug(hwc_procs, HWC_DISPLAY_EXTERNAL, true);
354 }
355 // Return 0, else client will go into bad state
356 return 0;
357 }
358
GetVsyncPeriod(int disp)359 int HWCSession::GetVsyncPeriod(int disp) {
360 SCOPE_LOCK(locker_);
361 // default value
362 int32_t vsync_period = 1000000000l / 60;
363 const uint32_t attribute = HWC_DISPLAY_VSYNC_PERIOD;
364
365 if (hwc_display_[disp]) {
366 hwc_display_[disp]->GetDisplayAttributes(0, &attribute, &vsync_period);
367 }
368
369 return vsync_period;
370 }
371
Set(hwc_composer_device_1 * device,size_t num_displays,hwc_display_contents_1_t ** displays)372 int HWCSession::Set(hwc_composer_device_1 *device, size_t num_displays,
373 hwc_display_contents_1_t **displays) {
374 DTRACE_SCOPED();
375
376 SEQUENCE_EXIT_SCOPE_LOCK(locker_);
377
378 if (!device || !displays || num_displays > HWC_NUM_DISPLAY_TYPES) {
379 return -EINVAL;
380 }
381
382 HWCSession *hwc_session = static_cast<HWCSession *>(device);
383
384 if (hwc_session->color_mgr_) {
385 HWCDisplay *primary_display = hwc_session->hwc_display_[HWC_DISPLAY_PRIMARY];
386 if (primary_display) {
387 int ret = hwc_session->color_mgr_->SolidFillLayersSet(displays, primary_display);
388 if (ret)
389 return 0;
390 hwc_session->color_mgr_->SetColorModeDetailEnhancer(primary_display);
391 }
392 }
393
394 for (size_t dpy = 0; dpy < num_displays; dpy++) {
395 hwc_display_contents_1_t *content_list = displays[dpy];
396
397 // Drop virtual display composition if virtual display object could not be created
398 // due to HDMI concurrency.
399 if (dpy == HWC_DISPLAY_VIRTUAL && !hwc_session->hwc_display_[HWC_DISPLAY_VIRTUAL]) {
400 CloseAcquireFds(content_list);
401 if (content_list) {
402 content_list->retireFenceFd = -1;
403 }
404
405 continue;
406 }
407
408 if (hwc_session->hwc_display_[dpy]) {
409 hwc_session->hwc_display_[dpy]->Commit(content_list);
410 }
411 CloseAcquireFds(content_list);
412 }
413
414 if (hwc_session->new_bw_mode_) {
415 hwc_display_contents_1_t *content_list = displays[HWC_DISPLAY_PRIMARY];
416 hwc_session->new_bw_mode_ = false;
417 if (hwc_session->bw_mode_release_fd_ >= 0) {
418 close(hwc_session->bw_mode_release_fd_);
419 }
420 hwc_session->bw_mode_release_fd_ = dup(content_list->retireFenceFd);
421 }
422
423 // This is only indicative of how many times SurfaceFlinger posts
424 // frames to the display.
425 CALC_FPS();
426
427 // Return 0, else client will go into bad state
428 return 0;
429 }
430
CloseAcquireFds(hwc_display_contents_1_t * content_list)431 void HWCSession::CloseAcquireFds(hwc_display_contents_1_t *content_list) {
432 if (content_list) {
433 for (size_t i = 0; i < content_list->numHwLayers; i++) {
434 int &acquireFenceFd = content_list->hwLayers[i].acquireFenceFd;
435 if (acquireFenceFd >= 0) {
436 close(acquireFenceFd);
437 acquireFenceFd = -1;
438 }
439 }
440
441 int &outbufAcquireFenceFd = content_list->outbufAcquireFenceFd;
442 if (outbufAcquireFenceFd >= 0) {
443 close(outbufAcquireFenceFd);
444 outbufAcquireFenceFd = -1;
445 }
446 }
447 }
448
IsDisplayYUV(int disp)449 bool HWCSession::IsDisplayYUV(int disp) {
450 int error = -EINVAL;
451 bool is_yuv = false;
452 DisplayConfigVariableInfo attributes = {};
453
454 if (disp < 0 || disp >= HWC_NUM_DISPLAY_TYPES || !hwc_display_[disp]) {
455 DLOGE("Invalid input parameters. Display = %d", disp);
456 return is_yuv;
457 }
458
459 uint32_t active_config = 0;
460 error = hwc_display_[disp]->GetActiveDisplayConfig(&active_config);
461 if (!error) {
462 error = hwc_display_[disp]->GetDisplayAttributesForConfig(INT(active_config), &attributes);
463 if (error == 0) {
464 is_yuv = attributes.is_yuv;
465 } else {
466 DLOGW("Error querying display attributes. Display = %d, Config = %d", disp, active_config);
467 }
468 }
469
470 return is_yuv;
471 }
472
EventControl(hwc_composer_device_1 * device,int disp,int event,int enable)473 int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event, int enable) {
474 SCOPE_LOCK(locker_);
475
476 if (!device) {
477 return -EINVAL;
478 }
479
480 HWCSession *hwc_session = static_cast<HWCSession *>(device);
481 int status = -EINVAL;
482 if (hwc_session->hwc_display_[disp]) {
483 status = hwc_session->hwc_display_[disp]->EventControl(event, enable);
484 }
485
486 return status;
487 }
488
SetPowerMode(hwc_composer_device_1 * device,int disp,int mode)489 int HWCSession::SetPowerMode(hwc_composer_device_1 *device, int disp, int mode) {
490 SEQUENCE_WAIT_SCOPE_LOCK(locker_);
491
492 if (!device) {
493 return -EINVAL;
494 }
495
496 HWCSession *hwc_session = static_cast<HWCSession *>(device);
497 int status = -EINVAL;
498 if (hwc_session->hwc_display_[disp]) {
499 status = hwc_session->hwc_display_[disp]->SetPowerMode(mode);
500 }
501
502 return status;
503 }
504
Query(hwc_composer_device_1 * device,int param,int * value)505 int HWCSession::Query(hwc_composer_device_1 *device, int param, int *value) {
506 SCOPE_LOCK(locker_);
507
508 if (!device || !value) {
509 return -EINVAL;
510 }
511
512 int status = 0;
513
514 switch (param) {
515 case HWC_BACKGROUND_LAYER_SUPPORTED:
516 value[0] = 1;
517 break;
518
519 default:
520 status = -EINVAL;
521 }
522
523 return status;
524 }
525
RegisterProcs(hwc_composer_device_1 * device,hwc_procs_t const * procs)526 void HWCSession::RegisterProcs(hwc_composer_device_1 *device, hwc_procs_t const *procs) {
527 SCOPE_LOCK(locker_);
528
529 if (!device || !procs) {
530 return;
531 }
532
533 HWCSession *hwc_session = static_cast<HWCSession *>(device);
534 hwc_session->hwc_procs_ = procs;
535 }
536
Dump(hwc_composer_device_1 * device,char * buffer,int length)537 void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) {
538 SEQUENCE_WAIT_SCOPE_LOCK(locker_);
539
540 if (!device || !buffer || !length) {
541 return;
542 }
543
544 DumpInterface::GetDump(buffer, UINT32(length));
545 }
546
GetDisplayConfigs(hwc_composer_device_1 * device,int disp,uint32_t * configs,size_t * num_configs)547 int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs,
548 size_t *num_configs) {
549 SCOPE_LOCK(locker_);
550
551 if (!device || !configs || !num_configs) {
552 return -EINVAL;
553 }
554
555 if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
556 return -EINVAL;
557 }
558
559 HWCSession *hwc_session = static_cast<HWCSession *>(device);
560 int status = -EINVAL;
561 if (hwc_session->hwc_display_[disp]) {
562 status = hwc_session->hwc_display_[disp]->GetDisplayConfigs(configs, num_configs);
563 }
564
565 return status;
566 }
567
GetDisplayAttributes(hwc_composer_device_1 * device,int disp,uint32_t config,const uint32_t * display_attributes,int32_t * values)568 int HWCSession::GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
569 const uint32_t *display_attributes, int32_t *values) {
570 SCOPE_LOCK(locker_);
571
572 if (!device || !display_attributes || !values) {
573 return -EINVAL;
574 }
575
576 if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
577 return -EINVAL;
578 }
579
580 HWCSession *hwc_session = static_cast<HWCSession *>(device);
581 int status = -EINVAL;
582 if (hwc_session->hwc_display_[disp]) {
583 status = hwc_session->hwc_display_[disp]->GetDisplayAttributes(config, display_attributes,
584 values);
585 }
586
587 return status;
588 }
589
GetActiveConfig(hwc_composer_device_1 * device,int disp)590 int HWCSession::GetActiveConfig(hwc_composer_device_1 *device, int disp) {
591 SCOPE_LOCK(locker_);
592
593 if (!device) {
594 return -EINVAL;
595 }
596
597 if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
598 return -EINVAL;
599 }
600
601 HWCSession *hwc_session = static_cast<HWCSession *>(device);
602 int active_config = -1;
603 if (hwc_session->hwc_display_[disp]) {
604 active_config = hwc_session->hwc_display_[disp]->GetActiveConfig();
605 }
606
607 return active_config;
608 }
609
SetActiveConfig(hwc_composer_device_1 * device,int disp,int index)610 int HWCSession::SetActiveConfig(hwc_composer_device_1 *device, int disp, int index) {
611 SEQUENCE_WAIT_SCOPE_LOCK(locker_);
612
613 if (!device) {
614 return -EINVAL;
615 }
616
617 if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
618 return -EINVAL;
619 }
620
621 HWCSession *hwc_session = static_cast<HWCSession *>(device);
622 int status = -EINVAL;
623
624 if (hwc_session->hwc_display_[disp]) {
625 status = hwc_session->hwc_display_[disp]->SetActiveConfig(index);
626 }
627
628 return status;
629 }
630
SetCursorPositionAsync(hwc_composer_device_1 * device,int disp,int x,int y)631 int HWCSession::SetCursorPositionAsync(hwc_composer_device_1 *device, int disp, int x, int y) {
632 DTRACE_SCOPED();
633
634 SCOPE_LOCK(locker_);
635
636 if (!device || (disp < HWC_DISPLAY_PRIMARY) || (disp > HWC_DISPLAY_VIRTUAL)) {
637 return -EINVAL;
638 }
639
640 int status = -EINVAL;
641 HWCSession *hwc_session = static_cast<HWCSession *>(device);
642 if (hwc_session->hwc_display_[disp]) {
643 status = hwc_session->hwc_display_[disp]->SetCursorPosition(x, y);
644 }
645
646 return status;
647 }
648
ConnectDisplay(int disp,hwc_display_contents_1_t * content_list)649 int HWCSession::ConnectDisplay(int disp, hwc_display_contents_1_t *content_list) {
650 DLOGI("Display = %d", disp);
651
652 int status = 0;
653 uint32_t primary_width = 0;
654 uint32_t primary_height = 0;
655
656 hwc_display_[HWC_DISPLAY_PRIMARY]->GetFrameBufferResolution(&primary_width, &primary_height);
657
658 if (disp == HWC_DISPLAY_EXTERNAL) {
659 status = CreateExternalDisplay(disp, primary_width, primary_height, false);
660 connected_displays_[HWC_DISPLAY_EXTERNAL] = 1;
661 } else if (disp == HWC_DISPLAY_VIRTUAL) {
662 status = HWCDisplayVirtual::Create(core_intf_, &hwc_procs_, primary_width, primary_height,
663 content_list, &hwc_display_[disp]);
664 connected_displays_[HWC_DISPLAY_VIRTUAL] = 1;
665 } else {
666 DLOGE("Invalid display type");
667 return -1;
668 }
669
670 if (!status) {
671 hwc_display_[disp]->SetSecureDisplay(secure_display_active_, true);
672 }
673
674 return status;
675 }
676
DisconnectDisplay(int disp)677 int HWCSession::DisconnectDisplay(int disp) {
678 DLOGI("Display = %d", disp);
679
680 if (disp == HWC_DISPLAY_EXTERNAL) {
681 HWCDisplayExternal::Destroy(hwc_display_[disp]);
682 connected_displays_[HWC_DISPLAY_EXTERNAL] = 0;
683 } else if (disp == HWC_DISPLAY_VIRTUAL) {
684 HWCDisplayVirtual::Destroy(hwc_display_[disp]);
685 connected_displays_[HWC_DISPLAY_VIRTUAL] = 0;
686 } else {
687 DLOGE("Invalid display type");
688 return -1;
689 }
690
691 hwc_display_[disp] = NULL;
692
693 return 0;
694 }
695
notifyCallback(uint32_t command,const android::Parcel * input_parcel,android::Parcel * output_parcel)696 android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel,
697 android::Parcel *output_parcel) {
698 SEQUENCE_WAIT_SCOPE_LOCK(locker_);
699
700 android::status_t status = 0;
701
702 switch (command) {
703 case qService::IQService::DYNAMIC_DEBUG:
704 DynamicDebug(input_parcel);
705 break;
706
707 case qService::IQService::SCREEN_REFRESH:
708 hwc_procs_->invalidate(hwc_procs_);
709 break;
710
711 case qService::IQService::SET_IDLE_TIMEOUT:
712 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
713 uint32_t timeout = UINT32(input_parcel->readInt32());
714 hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(timeout);
715 }
716 break;
717
718 case qService::IQService::SET_FRAME_DUMP_CONFIG:
719 SetFrameDumpConfig(input_parcel);
720 break;
721
722 case qService::IQService::SET_MAX_PIPES_PER_MIXER:
723 status = SetMaxMixerStages(input_parcel);
724 break;
725
726 case qService::IQService::SET_DISPLAY_MODE:
727 status = SetDisplayMode(input_parcel);
728 break;
729
730 case qService::IQService::SET_SECONDARY_DISPLAY_STATUS:
731 status = SetSecondaryDisplayStatus(input_parcel, output_parcel);
732 break;
733
734 case qService::IQService::CONFIGURE_DYN_REFRESH_RATE:
735 status = ConfigureRefreshRate(input_parcel);
736 break;
737
738 case qService::IQService::SET_VIEW_FRAME:
739 break;
740
741 case qService::IQService::TOGGLE_SCREEN_UPDATES:
742 status = ToggleScreenUpdates(input_parcel, output_parcel);
743 break;
744
745 case qService::IQService::QDCM_SVC_CMDS:
746 status = QdcmCMDHandler(input_parcel, output_parcel);
747 break;
748
749 case qService::IQService::MIN_HDCP_ENCRYPTION_LEVEL_CHANGED:
750 status = OnMinHdcpEncryptionLevelChange(input_parcel, output_parcel);
751 break;
752
753 case qService::IQService::CONTROL_PARTIAL_UPDATE:
754 status = ControlPartialUpdate(input_parcel, output_parcel);
755 break;
756
757 case qService::IQService::SET_ACTIVE_CONFIG:
758 status = HandleSetActiveDisplayConfig(input_parcel, output_parcel);
759 break;
760
761 case qService::IQService::GET_ACTIVE_CONFIG:
762 status = HandleGetActiveDisplayConfig(input_parcel, output_parcel);
763 break;
764
765 case qService::IQService::GET_CONFIG_COUNT:
766 status = HandleGetDisplayConfigCount(input_parcel, output_parcel);
767 break;
768
769 case qService::IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG:
770 status = HandleGetDisplayAttributesForConfig(input_parcel, output_parcel);
771 break;
772
773 case qService::IQService::GET_PANEL_BRIGHTNESS:
774 status = GetPanelBrightness(input_parcel, output_parcel);
775 break;
776
777 case qService::IQService::SET_PANEL_BRIGHTNESS:
778 status = SetPanelBrightness(input_parcel, output_parcel);
779 break;
780
781 case qService::IQService::GET_DISPLAY_VISIBLE_REGION:
782 status = GetVisibleDisplayRect(input_parcel, output_parcel);
783 break;
784
785 case qService::IQService::SET_CAMERA_STATUS:
786 status = SetDynamicBWForCamera(input_parcel, output_parcel);
787 break;
788
789 case qService::IQService::GET_BW_TRANSACTION_STATUS:
790 status = GetBWTransactionStatus(input_parcel, output_parcel);
791 break;
792
793 case qService::IQService::SET_LAYER_MIXER_RESOLUTION:
794 status = SetMixerResolution(input_parcel);
795 break;
796
797 case qService::IQService::GET_HDR_CAPABILITIES:
798 status = GetHdrCapabilities(input_parcel, output_parcel);
799 break;
800
801 default:
802 DLOGW("QService command = %d is not supported", command);
803 return -EINVAL;
804 }
805
806 return status;
807 }
808
ToggleScreenUpdates(const android::Parcel * input_parcel,android::Parcel * output_parcel)809 android::status_t HWCSession::ToggleScreenUpdates(const android::Parcel *input_parcel,
810 android::Parcel *output_parcel) {
811 int input = input_parcel->readInt32();
812 int error = android::BAD_VALUE;
813
814 if (hwc_display_[HWC_DISPLAY_PRIMARY] && (input <= 1) && (input >= 0)) {
815 error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(input == 1);
816 if (error != 0) {
817 DLOGE("Failed to toggle screen updates = %d. Error = %d", input, error);
818 }
819 }
820 output_parcel->writeInt32(error);
821
822 return error;
823 }
824
SetPanelBrightness(const android::Parcel * input_parcel,android::Parcel * output_parcel)825 android::status_t HWCSession::SetPanelBrightness(const android::Parcel *input_parcel,
826 android::Parcel *output_parcel) {
827 int level = input_parcel->readInt32();
828 int error = android::BAD_VALUE;
829
830 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
831 error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(level);
832 if (error != 0) {
833 DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error);
834 }
835 }
836 output_parcel->writeInt32(error);
837
838 return error;
839 }
840
GetPanelBrightness(const android::Parcel * input_parcel,android::Parcel * output_parcel)841 android::status_t HWCSession::GetPanelBrightness(const android::Parcel *input_parcel,
842 android::Parcel *output_parcel) {
843 int error = android::BAD_VALUE;
844 int ret = error;
845
846 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
847 error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(&ret);
848 if (error != 0) {
849 ret = error;
850 DLOGE("Failed to get the panel brightness. Error = %d", error);
851 }
852 }
853 output_parcel->writeInt32(ret);
854
855 return error;
856 }
857
ControlPartialUpdate(const android::Parcel * input_parcel,android::Parcel * out)858 android::status_t HWCSession::ControlPartialUpdate(const android::Parcel *input_parcel,
859 android::Parcel *out) {
860 DisplayError error = kErrorNone;
861 int ret = 0;
862 uint32_t disp_id = UINT32(input_parcel->readInt32());
863 uint32_t enable = UINT32(input_parcel->readInt32());
864
865 if (disp_id != HWC_DISPLAY_PRIMARY) {
866 DLOGW("CONTROL_PARTIAL_UPDATE is not applicable for display = %d", disp_id);
867 ret = -EINVAL;
868 out->writeInt32(ret);
869 return ret;
870 }
871
872 if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
873 DLOGE("primary display object is not instantiated");
874 ret = -EINVAL;
875 out->writeInt32(ret);
876 return ret;
877 }
878
879 uint32_t pending = 0;
880 error = hwc_display_[HWC_DISPLAY_PRIMARY]->ControlPartialUpdate(enable, &pending);
881
882 if (error == kErrorNone) {
883 if (!pending) {
884 out->writeInt32(ret);
885 return ret;
886 }
887 } else if (error == kErrorNotSupported) {
888 out->writeInt32(ret);
889 return ret;
890 } else {
891 ret = -EINVAL;
892 out->writeInt32(ret);
893 return ret;
894 }
895
896 // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future.
897 hwc_procs_->invalidate(hwc_procs_);
898
899 // Wait until partial update control is complete
900 ret = locker_.WaitFinite(kPartialUpdateControlTimeoutMs);
901
902 out->writeInt32(ret);
903
904 return ret;
905 }
906
HandleSetActiveDisplayConfig(const android::Parcel * input_parcel,android::Parcel * output_parcel)907 android::status_t HWCSession::HandleSetActiveDisplayConfig(const android::Parcel *input_parcel,
908 android::Parcel *output_parcel) {
909 int config = input_parcel->readInt32();
910 int dpy = input_parcel->readInt32();
911 int error = android::BAD_VALUE;
912
913 if (dpy > HWC_DISPLAY_VIRTUAL) {
914 return android::BAD_VALUE;
915 }
916
917 if (hwc_display_[dpy]) {
918 error = hwc_display_[dpy]->SetActiveDisplayConfig(config);
919 if (error == 0) {
920 hwc_procs_->invalidate(hwc_procs_);
921 }
922 }
923
924 return error;
925 }
926
HandleGetActiveDisplayConfig(const android::Parcel * input_parcel,android::Parcel * output_parcel)927 android::status_t HWCSession::HandleGetActiveDisplayConfig(const android::Parcel *input_parcel,
928 android::Parcel *output_parcel) {
929 int dpy = input_parcel->readInt32();
930 int error = android::BAD_VALUE;
931
932 if (dpy > HWC_DISPLAY_VIRTUAL) {
933 return android::BAD_VALUE;
934 }
935
936 if (hwc_display_[dpy]) {
937 uint32_t config = 0;
938 error = hwc_display_[dpy]->GetActiveDisplayConfig(&config);
939 if (error == 0) {
940 output_parcel->writeInt32(INT(config));
941 }
942 }
943
944 return error;
945 }
946
HandleGetDisplayConfigCount(const android::Parcel * input_parcel,android::Parcel * output_parcel)947 android::status_t HWCSession::HandleGetDisplayConfigCount(const android::Parcel *input_parcel,
948 android::Parcel *output_parcel) {
949 int dpy = input_parcel->readInt32();
950 int error = android::BAD_VALUE;
951
952 if (dpy > HWC_DISPLAY_VIRTUAL) {
953 return android::BAD_VALUE;
954 }
955
956 uint32_t count = 0;
957 if (hwc_display_[dpy]) {
958 error = hwc_display_[dpy]->GetDisplayConfigCount(&count);
959 if (error == 0) {
960 output_parcel->writeInt32(INT(count));
961 }
962 }
963
964 return error;
965 }
966
SetDisplayPort(DisplayPort sdm_disp_port,int * hwc_disp_port)967 android::status_t HWCSession::SetDisplayPort(DisplayPort sdm_disp_port, int *hwc_disp_port) {
968 if (!hwc_disp_port) {
969 return -EINVAL;
970 }
971
972 switch (sdm_disp_port) {
973 case kPortDSI:
974 *hwc_disp_port = qdutils::DISPLAY_PORT_DSI;
975 break;
976 case kPortDTV:
977 *hwc_disp_port = qdutils::DISPLAY_PORT_DTV;
978 break;
979 case kPortLVDS:
980 *hwc_disp_port = qdutils::DISPLAY_PORT_LVDS;
981 break;
982 case kPortEDP:
983 *hwc_disp_port = qdutils::DISPLAY_PORT_EDP;
984 break;
985 case kPortWriteBack:
986 *hwc_disp_port = qdutils::DISPLAY_PORT_WRITEBACK;
987 break;
988 case kPortDP:
989 *hwc_disp_port = qdutils::DISPLAY_PORT_DP;
990 break;
991 case kPortDefault:
992 *hwc_disp_port = qdutils::DISPLAY_PORT_DEFAULT;
993 break;
994 default:
995 DLOGE("Invalid sdm display port %d", sdm_disp_port);
996 return -EINVAL;
997 }
998
999 return 0;
1000 }
1001
HandleGetDisplayAttributesForConfig(const android::Parcel * input_parcel,android::Parcel * output_parcel)1002 android::status_t HWCSession::HandleGetDisplayAttributesForConfig(const android::Parcel
1003 *input_parcel,
1004 android::Parcel *output_parcel) {
1005 int config = input_parcel->readInt32();
1006 int dpy = input_parcel->readInt32();
1007 int error = android::BAD_VALUE;
1008 DisplayConfigVariableInfo display_attributes;
1009 DisplayPort sdm_disp_port = kPortDefault;
1010 int hwc_disp_port = qdutils::DISPLAY_PORT_DEFAULT;
1011
1012 if (dpy < HWC_DISPLAY_PRIMARY || dpy >= HWC_NUM_DISPLAY_TYPES || config < 0) {
1013 return android::BAD_VALUE;
1014 }
1015
1016 if (hwc_display_[dpy]) {
1017 error = hwc_display_[dpy]->GetDisplayAttributesForConfig(config, &display_attributes);
1018 if (error == 0) {
1019 hwc_display_[dpy]->GetDisplayPort(&sdm_disp_port);
1020
1021 SetDisplayPort(sdm_disp_port, &hwc_disp_port);
1022
1023 output_parcel->writeInt32(INT(display_attributes.vsync_period_ns));
1024 output_parcel->writeInt32(INT(display_attributes.x_pixels));
1025 output_parcel->writeInt32(INT(display_attributes.y_pixels));
1026 output_parcel->writeFloat(display_attributes.x_dpi);
1027 output_parcel->writeFloat(display_attributes.y_dpi);
1028 output_parcel->writeInt32(hwc_disp_port);
1029 output_parcel->writeInt32(display_attributes.is_yuv);
1030 }
1031 }
1032
1033 return error;
1034 }
1035
SetSecondaryDisplayStatus(const android::Parcel * input_parcel,android::Parcel * output_parcel)1036 android::status_t HWCSession::SetSecondaryDisplayStatus(const android::Parcel *input_parcel,
1037 android::Parcel *output_parcel) {
1038 int ret = -EINVAL;
1039
1040 uint32_t display_id = UINT32(input_parcel->readInt32());
1041 uint32_t display_status = UINT32(input_parcel->readInt32());
1042
1043 DLOGI("Display = %d, Status = %d", display_id, display_status);
1044
1045 if (display_id >= HWC_NUM_DISPLAY_TYPES) {
1046 DLOGE("Invalid display_id");
1047 } else if (display_id == HWC_DISPLAY_PRIMARY) {
1048 DLOGE("Not supported for this display");
1049 } else if (!hwc_display_[display_id]) {
1050 DLOGW("Display is not connected");
1051 } else {
1052 ret = hwc_display_[display_id]->SetDisplayStatus(display_status);
1053 }
1054
1055 output_parcel->writeInt32(ret);
1056
1057 return ret;
1058 }
1059
ConfigureRefreshRate(const android::Parcel * input_parcel)1060 android::status_t HWCSession::ConfigureRefreshRate(const android::Parcel *input_parcel) {
1061 uint32_t operation = UINT32(input_parcel->readInt32());
1062 switch (operation) {
1063 case qdutils::DISABLE_METADATA_DYN_REFRESH_RATE:
1064 return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
1065 HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
1066 case qdutils::ENABLE_METADATA_DYN_REFRESH_RATE:
1067 return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
1068 HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true);
1069 case qdutils::SET_BINDER_DYN_REFRESH_RATE:
1070 {
1071 uint32_t refresh_rate = UINT32(input_parcel->readInt32());
1072 return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
1073 HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE,
1074 refresh_rate);
1075 }
1076 default:
1077 DLOGW("Invalid operation %d", operation);
1078 return -EINVAL;
1079 }
1080
1081 return 0;
1082 }
1083
SetDisplayMode(const android::Parcel * input_parcel)1084 android::status_t HWCSession::SetDisplayMode(const android::Parcel *input_parcel) {
1085 uint32_t mode = UINT32(input_parcel->readInt32());
1086 return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(HWCDisplayPrimary::SET_DISPLAY_MODE, mode);
1087 }
1088
SetMaxMixerStages(const android::Parcel * input_parcel)1089 android::status_t HWCSession::SetMaxMixerStages(const android::Parcel *input_parcel) {
1090 DisplayError error = kErrorNone;
1091 std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32());
1092 uint32_t max_mixer_stages = UINT32(input_parcel->readInt32());
1093
1094 if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) {
1095 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
1096 error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetMaxMixerStages(max_mixer_stages);
1097 if (error != kErrorNone) {
1098 return -EINVAL;
1099 }
1100 }
1101 }
1102
1103 if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) {
1104 if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
1105 error = hwc_display_[HWC_DISPLAY_EXTERNAL]->SetMaxMixerStages(max_mixer_stages);
1106 if (error != kErrorNone) {
1107 return -EINVAL;
1108 }
1109 }
1110 }
1111
1112 if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) {
1113 if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
1114 error = hwc_display_[HWC_DISPLAY_VIRTUAL]->SetMaxMixerStages(max_mixer_stages);
1115 if (error != kErrorNone) {
1116 return -EINVAL;
1117 }
1118 }
1119 }
1120
1121 return 0;
1122 }
1123
SetDynamicBWForCamera(const android::Parcel * input_parcel,android::Parcel * output_parcel)1124 android::status_t HWCSession::SetDynamicBWForCamera(const android::Parcel *input_parcel,
1125 android::Parcel *output_parcel) {
1126 DisplayError error = kErrorNone;
1127 uint32_t camera_status = UINT32(input_parcel->readInt32());
1128 HWBwModes mode = camera_status > 0 ? kBwCamera : kBwDefault;
1129
1130 // trigger invalidate to apply new bw caps.
1131 hwc_procs_->invalidate(hwc_procs_);
1132
1133 error = core_intf_->SetMaxBandwidthMode(mode);
1134 if (error != kErrorNone) {
1135 return -EINVAL;
1136 }
1137
1138 new_bw_mode_ = true;
1139 need_invalidate_ = true;
1140
1141 return 0;
1142 }
1143
GetBWTransactionStatus(const android::Parcel * input_parcel,android::Parcel * output_parcel)1144 android::status_t HWCSession::GetBWTransactionStatus(const android::Parcel *input_parcel,
1145 android::Parcel *output_parcel) {
1146 bool state = true;
1147
1148 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
1149 if (sync_wait(bw_mode_release_fd_, 0) < 0) {
1150 DLOGI("bw_transaction_release_fd is not yet signalled: err= %s", strerror(errno));
1151 state = false;
1152 }
1153 output_parcel->writeInt32(state);
1154 }
1155
1156 return 0;
1157 }
1158
SetFrameDumpConfig(const android::Parcel * input_parcel)1159 void HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) {
1160 uint32_t frame_dump_count = UINT32(input_parcel->readInt32());
1161 std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32());
1162 uint32_t bit_mask_layer_type = UINT32(input_parcel->readInt32());
1163
1164 if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) {
1165 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
1166 hwc_display_[HWC_DISPLAY_PRIMARY]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
1167 }
1168 }
1169
1170 if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) {
1171 if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
1172 hwc_display_[HWC_DISPLAY_EXTERNAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
1173 }
1174 }
1175
1176 if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) {
1177 if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
1178 hwc_display_[HWC_DISPLAY_VIRTUAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
1179 }
1180 }
1181 }
1182
SetMixerResolution(const android::Parcel * input_parcel)1183 android::status_t HWCSession::SetMixerResolution(const android::Parcel *input_parcel) {
1184 DisplayError error = kErrorNone;
1185 uint32_t dpy = UINT32(input_parcel->readInt32());
1186
1187 if (dpy != HWC_DISPLAY_PRIMARY) {
1188 DLOGI("Resoulution change not supported for this display %d", dpy);
1189 return -EINVAL;
1190 }
1191
1192 if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
1193 DLOGI("Primary display is not initialized");
1194 return -EINVAL;
1195 }
1196
1197 uint32_t width = UINT32(input_parcel->readInt32());
1198 uint32_t height = UINT32(input_parcel->readInt32());
1199
1200 error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetMixerResolution(width, height);
1201 if (error != kErrorNone) {
1202 return -EINVAL;
1203 }
1204
1205 return 0;
1206 }
1207
GetHdrCapabilities(const android::Parcel * input_parcel,android::Parcel * output_parcel)1208 android::status_t HWCSession::GetHdrCapabilities(const android::Parcel *input_parcel,
1209 android::Parcel *output_parcel) {
1210 uint32_t display_id = UINT32(input_parcel->readInt32());
1211 if (display_id >= HWC_NUM_DISPLAY_TYPES) {
1212 DLOGE("Invalid display id = %d", display_id);
1213 return -EINVAL;
1214 }
1215
1216 if (hwc_display_[display_id] == NULL) {
1217 DLOGW("Display = %d not initialized", display_id);
1218 return -EINVAL;
1219 }
1220
1221 DisplayConfigFixedInfo fixed_info = {};
1222 int ret = hwc_display_[display_id]->GetDisplayFixedConfig(&fixed_info);
1223 if (ret) {
1224 DLOGE("Failed");
1225 return ret;
1226 }
1227
1228 if (!fixed_info.hdr_supported) {
1229 DLOGI("HDR is not supported");
1230 return 0;
1231 }
1232
1233 std::vector<int32_t> supported_hdr_types;
1234 // Only HDR10 supported now, in future add other supported HDR formats(HLG, DolbyVision)
1235 supported_hdr_types.push_back(HAL_HDR_HDR10);
1236
1237 static const float kLuminanceFactor = 10000.0;
1238 // luminance is expressed in the unit of 0.0001 cd/m2, convert it to 1cd/m2.
1239 float max_luminance = FLOAT(fixed_info.max_luminance)/kLuminanceFactor;
1240 float max_average_luminance = FLOAT(fixed_info.average_luminance)/kLuminanceFactor;
1241 float min_luminance = FLOAT(fixed_info.min_luminance)/kLuminanceFactor;
1242
1243 if (output_parcel != nullptr) {
1244 output_parcel->writeInt32Vector(supported_hdr_types);
1245 output_parcel->writeFloat(max_luminance);
1246 output_parcel->writeFloat(max_average_luminance);
1247 output_parcel->writeFloat(min_luminance);
1248 }
1249
1250 return 0;
1251 }
1252
DynamicDebug(const android::Parcel * input_parcel)1253 void HWCSession::DynamicDebug(const android::Parcel *input_parcel) {
1254 int type = input_parcel->readInt32();
1255 bool enable = (input_parcel->readInt32() > 0);
1256 DLOGI("type = %d enable = %d", type, enable);
1257 int verbose_level = input_parcel->readInt32();
1258
1259 switch (type) {
1260 case qService::IQService::DEBUG_ALL:
1261 HWCDebugHandler::DebugAll(enable, verbose_level);
1262 break;
1263
1264 case qService::IQService::DEBUG_MDPCOMP:
1265 HWCDebugHandler::DebugStrategy(enable, verbose_level);
1266 HWCDebugHandler::DebugCompManager(enable, verbose_level);
1267 break;
1268
1269 case qService::IQService::DEBUG_PIPE_LIFECYCLE:
1270 HWCDebugHandler::DebugResources(enable, verbose_level);
1271 break;
1272
1273 case qService::IQService::DEBUG_DRIVER_CONFIG:
1274 HWCDebugHandler::DebugDriverConfig(enable, verbose_level);
1275 break;
1276
1277 case qService::IQService::DEBUG_ROTATOR:
1278 HWCDebugHandler::DebugResources(enable, verbose_level);
1279 HWCDebugHandler::DebugDriverConfig(enable, verbose_level);
1280 HWCDebugHandler::DebugRotator(enable, verbose_level);
1281 break;
1282
1283 case qService::IQService::DEBUG_QDCM:
1284 HWCDebugHandler::DebugQdcm(enable, verbose_level);
1285 break;
1286
1287 default:
1288 DLOGW("type = %d is not supported", type);
1289 }
1290 }
1291
QdcmCMDHandler(const android::Parcel * input_parcel,android::Parcel * output_parcel)1292 android::status_t HWCSession::QdcmCMDHandler(const android::Parcel *input_parcel,
1293 android::Parcel *output_parcel) {
1294 int ret = 0;
1295 int32_t *brightness_value = NULL;
1296 uint32_t display_id(0);
1297 PPPendingParams pending_action;
1298 PPDisplayAPIPayload resp_payload, req_payload;
1299
1300 if (!color_mgr_) {
1301 return -1;
1302 }
1303
1304 pending_action.action = kNoAction;
1305 pending_action.params = NULL;
1306
1307 // Read display_id, payload_size and payload from in_parcel.
1308 ret = HWCColorManager::CreatePayloadFromParcel(*input_parcel, &display_id, &req_payload);
1309 if (!ret) {
1310 if (HWC_DISPLAY_PRIMARY == display_id && hwc_display_[HWC_DISPLAY_PRIMARY])
1311 ret = hwc_display_[HWC_DISPLAY_PRIMARY]->ColorSVCRequestRoute(req_payload,
1312 &resp_payload, &pending_action);
1313
1314 if (HWC_DISPLAY_EXTERNAL == display_id && hwc_display_[HWC_DISPLAY_EXTERNAL])
1315 ret = hwc_display_[HWC_DISPLAY_EXTERNAL]->ColorSVCRequestRoute(req_payload, &resp_payload,
1316 &pending_action);
1317 }
1318
1319 if (ret) {
1320 output_parcel->writeInt32(ret); // first field in out parcel indicates return code.
1321 req_payload.DestroyPayload();
1322 resp_payload.DestroyPayload();
1323 return ret;
1324 }
1325
1326 switch (pending_action.action) {
1327 case kInvalidating:
1328 hwc_procs_->invalidate(hwc_procs_);
1329 break;
1330 case kEnterQDCMMode:
1331 ret = color_mgr_->EnableQDCMMode(true, hwc_display_[HWC_DISPLAY_PRIMARY]);
1332 break;
1333 case kExitQDCMMode:
1334 ret = color_mgr_->EnableQDCMMode(false, hwc_display_[HWC_DISPLAY_PRIMARY]);
1335 break;
1336 case kApplySolidFill:
1337 ret = color_mgr_->SetSolidFill(pending_action.params,
1338 true, hwc_display_[HWC_DISPLAY_PRIMARY]);
1339 hwc_procs_->invalidate(hwc_procs_);
1340 break;
1341 case kDisableSolidFill:
1342 ret = color_mgr_->SetSolidFill(pending_action.params,
1343 false, hwc_display_[HWC_DISPLAY_PRIMARY]);
1344 hwc_procs_->invalidate(hwc_procs_);
1345 break;
1346 case kSetPanelBrightness:
1347 brightness_value = reinterpret_cast<int32_t*>(resp_payload.payload);
1348 if (brightness_value == NULL) {
1349 DLOGE("Brightness value is Null");
1350 return -EINVAL;
1351 }
1352 if (HWC_DISPLAY_PRIMARY == display_id)
1353 ret = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(*brightness_value);
1354 break;
1355 case kEnableFrameCapture:
1356 ret = color_mgr_->SetFrameCapture(pending_action.params,
1357 true, hwc_display_[HWC_DISPLAY_PRIMARY]);
1358 hwc_procs_->invalidate(hwc_procs_);
1359 break;
1360 case kDisableFrameCapture:
1361 ret = color_mgr_->SetFrameCapture(pending_action.params,
1362 false, hwc_display_[HWC_DISPLAY_PRIMARY]);
1363 break;
1364 case kConfigureDetailedEnhancer:
1365 ret = color_mgr_->SetDetailedEnhancer(pending_action.params,
1366 hwc_display_[HWC_DISPLAY_PRIMARY]);
1367 hwc_procs_->invalidate(hwc_procs_);
1368 break;
1369 case kInvalidatingAndkSetPanelBrightness:
1370 brightness_value = reinterpret_cast<int32_t*>(resp_payload.payload);
1371 if (brightness_value == NULL) {
1372 DLOGE("Brightness value is Null");
1373 return -EINVAL;
1374 }
1375 if (HWC_DISPLAY_PRIMARY == display_id)
1376 ret = hwc_display_[HWC_DISPLAY_PRIMARY]->CachePanelBrightness(*brightness_value);
1377 hwc_procs_->invalidate(hwc_procs_);
1378 break;
1379 case kNoAction:
1380 break;
1381 default:
1382 DLOGW("Invalid pending action = %d!", pending_action.action);
1383 break;
1384 }
1385
1386 // for display API getter case, marshall returned params into out_parcel.
1387 output_parcel->writeInt32(ret);
1388 HWCColorManager::MarshallStructIntoParcel(resp_payload, output_parcel);
1389 req_payload.DestroyPayload();
1390 resp_payload.DestroyPayload();
1391
1392 return (ret? -EINVAL : 0);
1393 }
1394
OnMinHdcpEncryptionLevelChange(const android::Parcel * input_parcel,android::Parcel * output_parcel)1395 android::status_t HWCSession::OnMinHdcpEncryptionLevelChange(const android::Parcel *input_parcel,
1396 android::Parcel *output_parcel) {
1397 int ret = -EINVAL;
1398 uint32_t display_id = UINT32(input_parcel->readInt32());
1399 uint32_t min_enc_level = UINT32(input_parcel->readInt32());
1400
1401 DLOGI("Display %d", display_id);
1402
1403 if (display_id >= HWC_NUM_DISPLAY_TYPES) {
1404 DLOGE("Invalid display_id");
1405 } else if (display_id != HWC_DISPLAY_EXTERNAL) {
1406 DLOGE("Not supported for display");
1407 } else if (!hwc_display_[display_id]) {
1408 DLOGW("Display is not connected");
1409 } else {
1410 ret = hwc_display_[display_id]->OnMinHdcpEncryptionLevelChange(min_enc_level);
1411 }
1412
1413 output_parcel->writeInt32(ret);
1414
1415 return ret;
1416 }
1417
HWCUeventThread(void * context)1418 void* HWCSession::HWCUeventThread(void *context) {
1419 if (context) {
1420 return reinterpret_cast<HWCSession *>(context)->HWCUeventThreadHandler();
1421 }
1422
1423 return NULL;
1424 }
1425
HWCUeventThreadHandler()1426 void* HWCSession::HWCUeventThreadHandler() {
1427 static char uevent_data[PAGE_SIZE];
1428 int length = 0;
1429
1430 uevent_locker_.Lock();
1431 prctl(PR_SET_NAME, uevent_thread_name_, 0, 0, 0);
1432 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
1433 if (!uevent_init()) {
1434 DLOGE("Failed to init uevent");
1435 pthread_exit(0);
1436 uevent_locker_.Signal();
1437 uevent_locker_.Unlock();
1438 return NULL;
1439 }
1440
1441 uevent_locker_.Signal();
1442 uevent_locker_.Unlock();
1443
1444 while (!uevent_thread_exit_) {
1445 // keep last 2 zeroes to ensure double 0 termination
1446 length = uevent_next_event(uevent_data, INT32(sizeof(uevent_data)) - 2);
1447
1448 if (strcasestr(HWC_UEVENT_SWITCH_HDMI, uevent_data)) {
1449 DLOGI("Uevent HDMI = %s", uevent_data);
1450 int connected = GetEventValue(uevent_data, length, "SWITCH_STATE=");
1451 if (connected >= 0) {
1452 DLOGI("HDMI = %s", connected ? "connected" : "disconnected");
1453 if (HotPlugHandler(connected) == -1) {
1454 DLOGE("Failed handling Hotplug = %s", connected ? "connected" : "disconnected");
1455 }
1456 }
1457 } else if (strcasestr(HWC_UEVENT_GRAPHICS_FB0, uevent_data)) {
1458 DLOGI("Uevent FB0 = %s", uevent_data);
1459 int panel_reset = GetEventValue(uevent_data, length, "PANEL_ALIVE=");
1460 if (panel_reset == 0) {
1461 if (hwc_procs_) {
1462 reset_panel_ = true;
1463 hwc_procs_->invalidate(hwc_procs_);
1464 } else {
1465 DLOGW("Ignore resetpanel - hwc_proc not registered");
1466 }
1467 }
1468 }
1469 }
1470 pthread_exit(0);
1471
1472 return NULL;
1473 }
1474
GetEventValue(const char * uevent_data,int length,const char * event_info)1475 int HWCSession::GetEventValue(const char *uevent_data, int length, const char *event_info) {
1476 const char *iterator_str = uevent_data;
1477 while (((iterator_str - uevent_data) <= length) && (*iterator_str)) {
1478 const char *pstr = strstr(iterator_str, event_info);
1479 if (pstr != NULL) {
1480 return (atoi(iterator_str + strlen(event_info)));
1481 }
1482 iterator_str += strlen(iterator_str) + 1;
1483 }
1484
1485 return -1;
1486 }
1487
ResetPanel()1488 void HWCSession::ResetPanel() {
1489 int status = -EINVAL;
1490
1491 DLOGI("Powering off primary");
1492 status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(HWC_POWER_MODE_OFF);
1493 if (status) {
1494 DLOGE("power-off on primary failed with error = %d", status);
1495 }
1496
1497 DLOGI("Restoring power mode on primary");
1498 int32_t mode = INT(hwc_display_[HWC_DISPLAY_PRIMARY]->GetLastPowerMode());
1499 status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(mode);
1500 if (status) {
1501 DLOGE("Setting power mode = %d on primary failed with error = %d", mode, status);
1502 }
1503
1504 status = hwc_display_[HWC_DISPLAY_PRIMARY]->EventControl(HWC_EVENT_VSYNC, 1);
1505 if (status) {
1506 DLOGE("enabling vsync failed for primary with error = %d", status);
1507 }
1508
1509 reset_panel_ = false;
1510 }
1511
HotPlugHandler(bool connected)1512 int HWCSession::HotPlugHandler(bool connected) {
1513 int status = 0;
1514 bool notify_hotplug = false;
1515 bool refresh_screen = false;
1516
1517 // To prevent sending events to client while a lock is held, acquire scope locks only within
1518 // below scope so that those get automatically unlocked after the scope ends.
1519 {
1520 SEQUENCE_WAIT_SCOPE_LOCK(locker_);
1521
1522 if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
1523 DLOGE("Primay display is not connected.");
1524 return -1;
1525 }
1526
1527
1528 HWCDisplay *primary_display = hwc_display_[HWC_DISPLAY_PRIMARY];
1529 HWCDisplay *external_display = NULL;
1530 HWCDisplay *null_display = NULL;
1531
1532 if (primary_display->GetDisplayClass() == DISPLAY_CLASS_EXTERNAL) {
1533 external_display = static_cast<HWCDisplayExternal *>(hwc_display_[HWC_DISPLAY_PRIMARY]);
1534 } else if (primary_display->GetDisplayClass() == DISPLAY_CLASS_NULL) {
1535 null_display = static_cast<HWCDisplayNull *>(hwc_display_[HWC_DISPLAY_PRIMARY]);
1536 }
1537
1538 // If primary display connected is a NULL display, then replace it with the external display
1539 if (connected) {
1540 // If we are in HDMI as primary and the primary display just got plugged in
1541 if (is_hdmi_primary_ && null_display) {
1542 uint32_t primary_width, primary_height;
1543 int status = 0;
1544 null_display->GetFrameBufferResolution(&primary_width, &primary_height);
1545 delete null_display;
1546 hwc_display_[HWC_DISPLAY_PRIMARY] = NULL;
1547
1548 // Create external display with a forced framebuffer resolution to that of what the NULL
1549 // display had. This is necessary because SurfaceFlinger does not dynamically update
1550 // framebuffer resolution once it reads it at bootup. So we always have to have the NULL
1551 // display/external display both at the bootup resolution.
1552 status = CreateExternalDisplay(HWC_DISPLAY_PRIMARY, primary_width, primary_height, true);
1553 if (status) {
1554 DLOGE("Could not create external display");
1555 return -1;
1556 }
1557
1558 status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(HWC_POWER_MODE_NORMAL);
1559 if (status) {
1560 DLOGE("power-on on primary failed with error = %d", status);
1561 }
1562
1563 is_hdmi_yuv_ = IsDisplayYUV(HWC_DISPLAY_PRIMARY);
1564
1565 // Next, go ahead and enable vsync on external display. This is expliclity required
1566 // because in HDMI as primary case, SurfaceFlinger may not be aware of underlying
1567 // changing display. and thus may not explicitly enable vsync
1568
1569 status = hwc_display_[HWC_DISPLAY_PRIMARY]->EventControl(HWC_EVENT_VSYNC, true);
1570 if (status) {
1571 DLOGE("Error enabling vsync for HDMI as primary case");
1572 }
1573 // Don't do hotplug notification for HDMI as primary case for now
1574 notify_hotplug = false;
1575 refresh_screen = true;
1576 } else {
1577 if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
1578 DLOGE("HDMI is already connected");
1579 return -1;
1580 }
1581
1582 // Connect external display if virtual display is not connected.
1583 // Else, defer external display connection and process it when virtual display
1584 // tears down; Do not notify SurfaceFlinger since connection is deferred now.
1585 if (!hwc_display_[HWC_DISPLAY_VIRTUAL]) {
1586 status = ConnectDisplay(HWC_DISPLAY_EXTERNAL, NULL);
1587 if (status) {
1588 return status;
1589 }
1590 notify_hotplug = true;
1591 } else {
1592 DLOGI("Virtual display is connected, pending connection");
1593 external_pending_connect_ = true;
1594 }
1595 }
1596 } else {
1597 // Do not return error if external display is not in connected status.
1598 // Due to virtual display concurrency, external display connection might be still pending
1599 // but hdmi got disconnected before pending connection could be processed.
1600
1601 if (is_hdmi_primary_ && external_display) {
1602 uint32_t x_res, y_res;
1603 external_display->GetFrameBufferResolution(&x_res, &y_res);
1604 // Need to manually disable VSYNC as SF is not aware of connect/disconnect cases
1605 // for HDMI as primary
1606 external_display->EventControl(HWC_EVENT_VSYNC, false);
1607 HWCDisplayExternal::Destroy(external_display);
1608
1609 HWCDisplayNull *null_display;
1610
1611 int status = HWCDisplayNull::Create(core_intf_, &hwc_procs_,
1612 reinterpret_cast<HWCDisplay **>(&null_display));
1613
1614 if (status) {
1615 DLOGE("Could not create Null display when primary got disconnected");
1616 return -1;
1617 }
1618
1619 null_display->SetResolution(x_res, y_res);
1620 hwc_display_[HWC_DISPLAY_PRIMARY] = null_display;
1621
1622 // Don't do hotplug notification for HDMI as primary case for now
1623 notify_hotplug = false;
1624 } else {
1625 if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
1626 status = DisconnectDisplay(HWC_DISPLAY_EXTERNAL);
1627 notify_hotplug = true;
1628 }
1629 external_pending_connect_ = false;
1630 }
1631 }
1632 }
1633
1634 if (connected && (notify_hotplug || refresh_screen)) {
1635 // trigger screen refresh to ensure sufficient resources are available to process new
1636 // new display connection.
1637 hwc_procs_->invalidate(hwc_procs_);
1638 uint32_t vsync_period = UINT32(GetVsyncPeriod(HWC_DISPLAY_PRIMARY));
1639 usleep(vsync_period * 2 / 1000);
1640 }
1641 // notify client
1642 if (notify_hotplug) {
1643 hwc_procs_->hotplug(hwc_procs_, HWC_DISPLAY_EXTERNAL, connected);
1644 }
1645
1646 qservice_->onHdmiHotplug(INT(connected));
1647
1648 return 0;
1649 }
1650
HandleSecureDisplaySession(hwc_display_contents_1_t ** displays)1651 void HWCSession::HandleSecureDisplaySession(hwc_display_contents_1_t **displays) {
1652 secure_display_active_ = false;
1653 if (!*displays) {
1654 DLOGW("Invalid display contents");
1655 return;
1656 }
1657
1658 hwc_display_contents_1_t *content_list = displays[HWC_DISPLAY_PRIMARY];
1659 if (!content_list) {
1660 DLOGW("Invalid primary content list");
1661 return;
1662 }
1663 size_t num_hw_layers = content_list->numHwLayers;
1664
1665 for (size_t i = 0; i < num_hw_layers - 1; i++) {
1666 hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
1667 const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer.handle);
1668 if (pvt_handle && pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY) {
1669 secure_display_active_ = true;
1670 }
1671 }
1672
1673 // Force flush on primary during transitions(secure<->non secure)
1674 // when external displays are connected.
1675 bool force_flush = false;
1676 if ((connected_displays_[HWC_DISPLAY_PRIMARY] == 1) &&
1677 ((connected_displays_[HWC_DISPLAY_EXTERNAL] == 1) ||
1678 (connected_displays_[HWC_DISPLAY_VIRTUAL] == 1))) {
1679 force_flush = true;
1680 }
1681
1682 for (ssize_t dpy = static_cast<ssize_t>(HWC_NUM_DISPLAY_TYPES - 1); dpy >= 0; dpy--) {
1683 if (hwc_display_[dpy]) {
1684 hwc_display_[dpy]->SetSecureDisplay(secure_display_active_, force_flush);
1685 }
1686 }
1687 }
1688
GetVisibleDisplayRect(const android::Parcel * input_parcel,android::Parcel * output_parcel)1689 android::status_t HWCSession::GetVisibleDisplayRect(const android::Parcel *input_parcel,
1690 android::Parcel *output_parcel) {
1691 int dpy = input_parcel->readInt32();
1692
1693 if (dpy < HWC_DISPLAY_PRIMARY || dpy >= HWC_NUM_DISPLAY_TYPES) {
1694 return android::BAD_VALUE;;
1695 }
1696
1697 if (!hwc_display_[dpy]) {
1698 return android::NO_INIT;
1699 }
1700
1701 hwc_rect_t visible_rect = {0, 0, 0, 0};
1702 int error = hwc_display_[dpy]->GetVisibleDisplayRect(&visible_rect);
1703 if (error < 0) {
1704 return error;
1705 }
1706
1707 output_parcel->writeInt32(visible_rect.left);
1708 output_parcel->writeInt32(visible_rect.top);
1709 output_parcel->writeInt32(visible_rect.right);
1710 output_parcel->writeInt32(visible_rect.bottom);
1711
1712 return android::NO_ERROR;
1713 }
1714
CreateExternalDisplay(int disp,uint32_t primary_width,uint32_t primary_height,bool use_primary_res)1715 int HWCSession::CreateExternalDisplay(int disp, uint32_t primary_width, uint32_t primary_height,
1716 bool use_primary_res) {
1717 uint32_t panel_bpp = 0;
1718 uint32_t pattern_type = 0;
1719
1720 if (qdutils::isDPConnected()) {
1721 qdutils::getDPTestConfig(&panel_bpp, &pattern_type);
1722 }
1723
1724 if (panel_bpp && pattern_type) {
1725 return HWCDisplayExternalTest::Create(core_intf_, &hwc_procs_, qservice_, panel_bpp,
1726 pattern_type, &hwc_display_[disp]);
1727 }
1728
1729 return HWCDisplayExternal::Create(core_intf_, &hwc_procs_, primary_width, primary_height,
1730 qservice_, use_primary_res, &hwc_display_[disp]);
1731 }
1732
1733 } // namespace sdm
1734
1735