1 /*
2 * Copyright (c) 2014 - 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/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_session->AsyncRefresh();
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 locker_.Signal();
424
425 // This is only indicative of how many times SurfaceFlinger posts
426 // frames to the display.
427 CALC_FPS();
428
429 // Return 0, else client will go into bad state
430 return 0;
431 }
432
CloseAcquireFds(hwc_display_contents_1_t * content_list)433 void HWCSession::CloseAcquireFds(hwc_display_contents_1_t *content_list) {
434 if (content_list) {
435 for (size_t i = 0; i < content_list->numHwLayers; i++) {
436 int &acquireFenceFd = content_list->hwLayers[i].acquireFenceFd;
437 if (acquireFenceFd >= 0) {
438 close(acquireFenceFd);
439 acquireFenceFd = -1;
440 }
441 }
442
443 int &outbufAcquireFenceFd = content_list->outbufAcquireFenceFd;
444 if (outbufAcquireFenceFd >= 0) {
445 close(outbufAcquireFenceFd);
446 outbufAcquireFenceFd = -1;
447 }
448 }
449 }
450
IsDisplayYUV(int disp)451 bool HWCSession::IsDisplayYUV(int disp) {
452 int error = -EINVAL;
453 bool is_yuv = false;
454 DisplayConfigVariableInfo attributes = {};
455
456 if (disp < 0 || disp >= HWC_NUM_DISPLAY_TYPES || !hwc_display_[disp]) {
457 DLOGE("Invalid input parameters. Display = %d", disp);
458 return is_yuv;
459 }
460
461 uint32_t active_config = 0;
462 error = hwc_display_[disp]->GetActiveDisplayConfig(&active_config);
463 if (!error) {
464 error = hwc_display_[disp]->GetDisplayAttributesForConfig(INT(active_config), &attributes);
465 if (error == 0) {
466 is_yuv = attributes.is_yuv;
467 } else {
468 DLOGW("Error querying display attributes. Display = %d, Config = %d", disp, active_config);
469 }
470 }
471
472 return is_yuv;
473 }
474
EventControl(hwc_composer_device_1 * device,int disp,int event,int enable)475 int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event, int enable) {
476 SCOPE_LOCK(locker_);
477
478 if (!device) {
479 return -EINVAL;
480 }
481
482 HWCSession *hwc_session = static_cast<HWCSession *>(device);
483 int status = -EINVAL;
484 if (hwc_session->hwc_display_[disp]) {
485 status = hwc_session->hwc_display_[disp]->EventControl(event, enable);
486 }
487
488 return status;
489 }
490
SetPowerMode(hwc_composer_device_1 * device,int disp,int mode)491 int HWCSession::SetPowerMode(hwc_composer_device_1 *device, int disp, int mode) {
492 SEQUENCE_WAIT_SCOPE_LOCK(locker_);
493
494 if (!device) {
495 return -EINVAL;
496 }
497
498 HWCSession *hwc_session = static_cast<HWCSession *>(device);
499 int status = -EINVAL;
500 if (hwc_session->hwc_display_[disp]) {
501 status = hwc_session->hwc_display_[disp]->SetPowerMode(mode);
502 }
503
504 return status;
505 }
506
Query(hwc_composer_device_1 * device,int param,int * value)507 int HWCSession::Query(hwc_composer_device_1 *device, int param, int *value) {
508 SCOPE_LOCK(locker_);
509
510 if (!device || !value) {
511 return -EINVAL;
512 }
513
514 int status = 0;
515
516 switch (param) {
517 case HWC_BACKGROUND_LAYER_SUPPORTED:
518 value[0] = 1;
519 break;
520
521 default:
522 status = -EINVAL;
523 }
524
525 return status;
526 }
527
RegisterProcs(hwc_composer_device_1 * device,hwc_procs_t const * procs)528 void HWCSession::RegisterProcs(hwc_composer_device_1 *device, hwc_procs_t const *procs) {
529 SCOPE_LOCK(locker_);
530
531 if (!device || !procs) {
532 return;
533 }
534
535 HWCSession *hwc_session = static_cast<HWCSession *>(device);
536 hwc_session->hwc_procs_ = procs;
537 }
538
Dump(hwc_composer_device_1 * device,char * buffer,int length)539 void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) {
540 SEQUENCE_WAIT_SCOPE_LOCK(locker_);
541
542 if (!device || !buffer || !length) {
543 return;
544 }
545
546 DumpInterface::GetDump(buffer, UINT32(length));
547 }
548
GetDisplayConfigs(hwc_composer_device_1 * device,int disp,uint32_t * configs,size_t * num_configs)549 int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs,
550 size_t *num_configs) {
551 SCOPE_LOCK(locker_);
552
553 if (!device || !configs || !num_configs) {
554 return -EINVAL;
555 }
556
557 if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
558 return -EINVAL;
559 }
560
561 HWCSession *hwc_session = static_cast<HWCSession *>(device);
562 int status = -EINVAL;
563 if (hwc_session->hwc_display_[disp]) {
564 status = hwc_session->hwc_display_[disp]->GetDisplayConfigs(configs, num_configs);
565 }
566
567 return status;
568 }
569
GetDisplayAttributes(hwc_composer_device_1 * device,int disp,uint32_t config,const uint32_t * display_attributes,int32_t * values)570 int HWCSession::GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
571 const uint32_t *display_attributes, int32_t *values) {
572 SCOPE_LOCK(locker_);
573
574 if (!device || !display_attributes || !values) {
575 return -EINVAL;
576 }
577
578 if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
579 return -EINVAL;
580 }
581
582 HWCSession *hwc_session = static_cast<HWCSession *>(device);
583 int status = -EINVAL;
584 if (hwc_session->hwc_display_[disp]) {
585 status = hwc_session->hwc_display_[disp]->GetDisplayAttributes(config, display_attributes,
586 values);
587 }
588
589 return status;
590 }
591
GetActiveConfig(hwc_composer_device_1 * device,int disp)592 int HWCSession::GetActiveConfig(hwc_composer_device_1 *device, int disp) {
593 SCOPE_LOCK(locker_);
594
595 if (!device) {
596 return -EINVAL;
597 }
598
599 if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
600 return -EINVAL;
601 }
602
603 HWCSession *hwc_session = static_cast<HWCSession *>(device);
604 int active_config = -1;
605 if (hwc_session->hwc_display_[disp]) {
606 active_config = hwc_session->hwc_display_[disp]->GetActiveConfig();
607 }
608
609 return active_config;
610 }
611
SetActiveConfig(hwc_composer_device_1 * device,int disp,int index)612 int HWCSession::SetActiveConfig(hwc_composer_device_1 *device, int disp, int index) {
613 SEQUENCE_WAIT_SCOPE_LOCK(locker_);
614
615 if (!device) {
616 return -EINVAL;
617 }
618
619 if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
620 return -EINVAL;
621 }
622
623 HWCSession *hwc_session = static_cast<HWCSession *>(device);
624 int status = -EINVAL;
625
626 if (hwc_session->hwc_display_[disp]) {
627 status = hwc_session->hwc_display_[disp]->SetActiveConfig(index);
628 }
629
630 return status;
631 }
632
SetCursorPositionAsync(hwc_composer_device_1 * device,int disp,int x,int y)633 int HWCSession::SetCursorPositionAsync(hwc_composer_device_1 *device, int disp, int x, int y) {
634 DTRACE_SCOPED();
635
636 SCOPE_LOCK(locker_);
637
638 if (!device || (disp < HWC_DISPLAY_PRIMARY) || (disp > HWC_DISPLAY_VIRTUAL)) {
639 return -EINVAL;
640 }
641
642 int status = -EINVAL;
643 HWCSession *hwc_session = static_cast<HWCSession *>(device);
644 if (hwc_session->hwc_display_[disp]) {
645 status = hwc_session->hwc_display_[disp]->SetCursorPosition(x, y);
646 }
647
648 return status;
649 }
650
ConnectDisplay(int disp,hwc_display_contents_1_t * content_list)651 int HWCSession::ConnectDisplay(int disp, hwc_display_contents_1_t *content_list) {
652 DLOGI("Display = %d", disp);
653
654 int status = 0;
655 uint32_t primary_width = 0;
656 uint32_t primary_height = 0;
657
658 hwc_display_[HWC_DISPLAY_PRIMARY]->GetFrameBufferResolution(&primary_width, &primary_height);
659
660 if (disp == HWC_DISPLAY_EXTERNAL) {
661 status = CreateExternalDisplay(disp, primary_width, primary_height, false);
662 connected_displays_[HWC_DISPLAY_EXTERNAL] = 1;
663 } else if (disp == HWC_DISPLAY_VIRTUAL) {
664 status = HWCDisplayVirtual::Create(core_intf_, &hwc_procs_, primary_width, primary_height,
665 content_list, &hwc_display_[disp]);
666 connected_displays_[HWC_DISPLAY_VIRTUAL] = 1;
667 } else {
668 DLOGE("Invalid display type");
669 return -1;
670 }
671
672 if (!status) {
673 hwc_display_[disp]->SetSecureDisplay(secure_display_active_, true);
674 }
675
676 return status;
677 }
678
DisconnectDisplay(int disp)679 int HWCSession::DisconnectDisplay(int disp) {
680 DLOGI("Display = %d", disp);
681
682 if (disp == HWC_DISPLAY_EXTERNAL) {
683 HWCDisplayExternal::Destroy(hwc_display_[disp]);
684 connected_displays_[HWC_DISPLAY_EXTERNAL] = 0;
685 } else if (disp == HWC_DISPLAY_VIRTUAL) {
686 HWCDisplayVirtual::Destroy(hwc_display_[disp]);
687 connected_displays_[HWC_DISPLAY_VIRTUAL] = 0;
688 } else {
689 DLOGE("Invalid display type");
690 return -1;
691 }
692
693 hwc_display_[disp] = NULL;
694
695 return 0;
696 }
697
PostRefresh(hwc_procs_t const * hwc_procs)698 static void PostRefresh(hwc_procs_t const *hwc_procs) {
699 hwc_procs->invalidate(hwc_procs);
700 }
701
AsyncRefresh()702 void HWCSession::AsyncRefresh() {
703 future_ = std::async(PostRefresh, hwc_procs_);
704 }
705
notifyCallback(uint32_t command,const android::Parcel * input_parcel,android::Parcel * output_parcel)706 android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel,
707 android::Parcel *output_parcel) {
708 SEQUENCE_WAIT_SCOPE_LOCK(locker_);
709
710 android::status_t status = 0;
711
712 switch (command) {
713 case qService::IQService::DYNAMIC_DEBUG:
714 DynamicDebug(input_parcel);
715 break;
716
717 case qService::IQService::SCREEN_REFRESH:
718 AsyncRefresh();
719 break;
720
721 case qService::IQService::SET_IDLE_TIMEOUT:
722 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
723 uint32_t timeout = UINT32(input_parcel->readInt32());
724 hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(timeout);
725 }
726 break;
727
728 case qService::IQService::SET_FRAME_DUMP_CONFIG:
729 SetFrameDumpConfig(input_parcel);
730 break;
731
732 case qService::IQService::SET_MAX_PIPES_PER_MIXER:
733 status = SetMaxMixerStages(input_parcel);
734 break;
735
736 case qService::IQService::SET_DISPLAY_MODE:
737 status = SetDisplayMode(input_parcel);
738 break;
739
740 case qService::IQService::SET_SECONDARY_DISPLAY_STATUS:
741 status = SetSecondaryDisplayStatus(input_parcel, output_parcel);
742 break;
743
744 case qService::IQService::CONFIGURE_DYN_REFRESH_RATE:
745 status = ConfigureRefreshRate(input_parcel);
746 break;
747
748 case qService::IQService::SET_VIEW_FRAME:
749 break;
750
751 case qService::IQService::TOGGLE_SCREEN_UPDATES:
752 status = ToggleScreenUpdates(input_parcel, output_parcel);
753 break;
754
755 case qService::IQService::QDCM_SVC_CMDS:
756 status = QdcmCMDHandler(input_parcel, output_parcel);
757 break;
758
759 case qService::IQService::MIN_HDCP_ENCRYPTION_LEVEL_CHANGED:
760 status = OnMinHdcpEncryptionLevelChange(input_parcel, output_parcel);
761 break;
762
763 case qService::IQService::CONTROL_PARTIAL_UPDATE:
764 status = ControlPartialUpdate(input_parcel, output_parcel);
765 break;
766
767 case qService::IQService::SET_ACTIVE_CONFIG:
768 status = HandleSetActiveDisplayConfig(input_parcel, output_parcel);
769 break;
770
771 case qService::IQService::GET_ACTIVE_CONFIG:
772 status = HandleGetActiveDisplayConfig(input_parcel, output_parcel);
773 break;
774
775 case qService::IQService::GET_CONFIG_COUNT:
776 status = HandleGetDisplayConfigCount(input_parcel, output_parcel);
777 break;
778
779 case qService::IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG:
780 status = HandleGetDisplayAttributesForConfig(input_parcel, output_parcel);
781 break;
782
783 case qService::IQService::GET_PANEL_BRIGHTNESS:
784 status = GetPanelBrightness(input_parcel, output_parcel);
785 break;
786
787 case qService::IQService::SET_PANEL_BRIGHTNESS:
788 status = SetPanelBrightness(input_parcel, output_parcel);
789 break;
790
791 case qService::IQService::GET_DISPLAY_VISIBLE_REGION:
792 status = GetVisibleDisplayRect(input_parcel, output_parcel);
793 break;
794
795 case qService::IQService::SET_CAMERA_STATUS:
796 status = SetDynamicBWForCamera(input_parcel, output_parcel);
797 break;
798
799 case qService::IQService::GET_BW_TRANSACTION_STATUS:
800 status = GetBWTransactionStatus(input_parcel, output_parcel);
801 break;
802
803 case qService::IQService::SET_LAYER_MIXER_RESOLUTION:
804 status = SetMixerResolution(input_parcel);
805 break;
806
807 case qService::IQService::GET_HDR_CAPABILITIES:
808 status = GetHdrCapabilities(input_parcel, output_parcel);
809 break;
810
811 default:
812 DLOGW("QService command = %d is not supported", command);
813 return -EINVAL;
814 }
815
816 return status;
817 }
818
ToggleScreenUpdates(const android::Parcel * input_parcel,android::Parcel * output_parcel)819 android::status_t HWCSession::ToggleScreenUpdates(const android::Parcel *input_parcel,
820 android::Parcel *output_parcel) {
821 int input = input_parcel->readInt32();
822 int error = android::BAD_VALUE;
823
824 if (hwc_display_[HWC_DISPLAY_PRIMARY] && (input <= 1) && (input >= 0)) {
825 error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(input == 1);
826 if (error != 0) {
827 DLOGE("Failed to toggle screen updates = %d. Error = %d", input, error);
828 }
829 }
830 output_parcel->writeInt32(error);
831
832 return error;
833 }
834
SetPanelBrightness(const android::Parcel * input_parcel,android::Parcel * output_parcel)835 android::status_t HWCSession::SetPanelBrightness(const android::Parcel *input_parcel,
836 android::Parcel *output_parcel) {
837 int level = input_parcel->readInt32();
838 int error = android::BAD_VALUE;
839
840 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
841 error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(level);
842 if (error != 0) {
843 DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error);
844 }
845 }
846 output_parcel->writeInt32(error);
847
848 return error;
849 }
850
GetPanelBrightness(const android::Parcel * input_parcel,android::Parcel * output_parcel)851 android::status_t HWCSession::GetPanelBrightness(const android::Parcel *input_parcel,
852 android::Parcel *output_parcel) {
853 int error = android::BAD_VALUE;
854 int ret = error;
855
856 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
857 error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(&ret);
858 if (error != 0) {
859 ret = error;
860 DLOGE("Failed to get the panel brightness. Error = %d", error);
861 }
862 }
863 output_parcel->writeInt32(ret);
864
865 return error;
866 }
867
ControlPartialUpdate(const android::Parcel * input_parcel,android::Parcel * output_parcel)868 android::status_t HWCSession::ControlPartialUpdate(const android::Parcel *input_parcel,
869 android::Parcel *output_parcel) {
870 DisplayError error = kErrorNone;
871 int ret = 0;
872 uint32_t disp_id = UINT32(input_parcel->readInt32());
873 uint32_t enable = UINT32(input_parcel->readInt32());
874
875 if (disp_id != HWC_DISPLAY_PRIMARY) {
876 DLOGW("CONTROL_PARTIAL_UPDATE is not applicable for display = %d", disp_id);
877 ret = -EINVAL;
878 output_parcel->writeInt32(ret);
879 return ret;
880 }
881
882 if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
883 DLOGE("primary display object is not instantiated");
884 ret = -EINVAL;
885 output_parcel->writeInt32(ret);
886 return ret;
887 }
888
889 uint32_t pending = 0;
890 error = hwc_display_[HWC_DISPLAY_PRIMARY]->ControlPartialUpdate(enable, &pending);
891
892 if (error == kErrorNone) {
893 if (!pending) {
894 output_parcel->writeInt32(ret);
895 return ret;
896 }
897 } else if (error == kErrorNotSupported) {
898 output_parcel->writeInt32(ret);
899 return ret;
900 } else {
901 ret = -EINVAL;
902 output_parcel->writeInt32(ret);
903 return ret;
904 }
905
906 AsyncRefresh();
907
908 // Wait until partial update control is complete
909 ret = locker_.WaitFinite(kPartialUpdateControlTimeoutMs);
910
911 output_parcel->writeInt32(ret);
912
913 return ret;
914 }
915
HandleSetActiveDisplayConfig(const android::Parcel * input_parcel,android::Parcel * output_parcel)916 android::status_t HWCSession::HandleSetActiveDisplayConfig(const android::Parcel *input_parcel,
917 android::Parcel *output_parcel) {
918 int config = input_parcel->readInt32();
919 int dpy = input_parcel->readInt32();
920 int error = android::BAD_VALUE;
921
922 if (dpy > HWC_DISPLAY_VIRTUAL) {
923 return android::BAD_VALUE;
924 }
925
926 if (hwc_display_[dpy]) {
927 error = hwc_display_[dpy]->SetActiveDisplayConfig(config);
928 if (error == 0) {
929 AsyncRefresh();
930 }
931 }
932
933 return error;
934 }
935
HandleGetActiveDisplayConfig(const android::Parcel * input_parcel,android::Parcel * output_parcel)936 android::status_t HWCSession::HandleGetActiveDisplayConfig(const android::Parcel *input_parcel,
937 android::Parcel *output_parcel) {
938 int dpy = input_parcel->readInt32();
939 int error = android::BAD_VALUE;
940
941 if (dpy > HWC_DISPLAY_VIRTUAL) {
942 return android::BAD_VALUE;
943 }
944
945 if (hwc_display_[dpy]) {
946 uint32_t config = 0;
947 error = hwc_display_[dpy]->GetActiveDisplayConfig(&config);
948 if (error == 0) {
949 output_parcel->writeInt32(INT(config));
950 }
951 }
952
953 return error;
954 }
955
HandleGetDisplayConfigCount(const android::Parcel * input_parcel,android::Parcel * output_parcel)956 android::status_t HWCSession::HandleGetDisplayConfigCount(const android::Parcel *input_parcel,
957 android::Parcel *output_parcel) {
958 int dpy = input_parcel->readInt32();
959 int error = android::BAD_VALUE;
960
961 if (dpy > HWC_DISPLAY_VIRTUAL) {
962 return android::BAD_VALUE;
963 }
964
965 uint32_t count = 0;
966 if (hwc_display_[dpy]) {
967 error = hwc_display_[dpy]->GetDisplayConfigCount(&count);
968 if (error == 0) {
969 output_parcel->writeInt32(INT(count));
970 }
971 }
972
973 return error;
974 }
975
SetDisplayPort(DisplayPort sdm_disp_port,int * hwc_disp_port)976 android::status_t HWCSession::SetDisplayPort(DisplayPort sdm_disp_port, int *hwc_disp_port) {
977 if (!hwc_disp_port) {
978 return -EINVAL;
979 }
980
981 switch (sdm_disp_port) {
982 case kPortDSI:
983 *hwc_disp_port = qdutils::DISPLAY_PORT_DSI;
984 break;
985 case kPortDTV:
986 *hwc_disp_port = qdutils::DISPLAY_PORT_DTV;
987 break;
988 case kPortLVDS:
989 *hwc_disp_port = qdutils::DISPLAY_PORT_LVDS;
990 break;
991 case kPortEDP:
992 *hwc_disp_port = qdutils::DISPLAY_PORT_EDP;
993 break;
994 case kPortWriteBack:
995 *hwc_disp_port = qdutils::DISPLAY_PORT_WRITEBACK;
996 break;
997 case kPortDP:
998 *hwc_disp_port = qdutils::DISPLAY_PORT_DP;
999 break;
1000 case kPortDefault:
1001 *hwc_disp_port = qdutils::DISPLAY_PORT_DEFAULT;
1002 break;
1003 default:
1004 DLOGE("Invalid sdm display port %d", sdm_disp_port);
1005 return -EINVAL;
1006 }
1007
1008 return 0;
1009 }
1010
HandleGetDisplayAttributesForConfig(const android::Parcel * input_parcel,android::Parcel * output_parcel)1011 android::status_t HWCSession::HandleGetDisplayAttributesForConfig(const android::Parcel
1012 *input_parcel,
1013 android::Parcel *output_parcel) {
1014 int config = input_parcel->readInt32();
1015 int dpy = input_parcel->readInt32();
1016 int error = android::BAD_VALUE;
1017 DisplayConfigVariableInfo display_attributes;
1018 DisplayPort sdm_disp_port = kPortDefault;
1019 int hwc_disp_port = qdutils::DISPLAY_PORT_DEFAULT;
1020
1021 if (dpy > HWC_DISPLAY_VIRTUAL) {
1022 return android::BAD_VALUE;
1023 }
1024
1025 if (hwc_display_[dpy]) {
1026 error = hwc_display_[dpy]->GetDisplayAttributesForConfig(config, &display_attributes);
1027 if (error == 0) {
1028 hwc_display_[dpy]->GetDisplayPort(&sdm_disp_port);
1029
1030 SetDisplayPort(sdm_disp_port, &hwc_disp_port);
1031
1032 output_parcel->writeInt32(INT(display_attributes.vsync_period_ns));
1033 output_parcel->writeInt32(INT(display_attributes.x_pixels));
1034 output_parcel->writeInt32(INT(display_attributes.y_pixels));
1035 output_parcel->writeFloat(display_attributes.x_dpi);
1036 output_parcel->writeFloat(display_attributes.y_dpi);
1037 output_parcel->writeInt32(hwc_disp_port);
1038 output_parcel->writeInt32(display_attributes.is_yuv);
1039 }
1040 }
1041
1042 return error;
1043 }
1044
SetSecondaryDisplayStatus(const android::Parcel * input_parcel,android::Parcel * output_parcel)1045 android::status_t HWCSession::SetSecondaryDisplayStatus(const android::Parcel *input_parcel,
1046 android::Parcel *output_parcel) {
1047 int ret = -EINVAL;
1048
1049 uint32_t display_id = UINT32(input_parcel->readInt32());
1050 uint32_t display_status = UINT32(input_parcel->readInt32());
1051
1052 DLOGI("Display = %d, Status = %d", display_id, display_status);
1053
1054 if (display_id >= HWC_NUM_DISPLAY_TYPES) {
1055 DLOGE("Invalid display_id");
1056 } else if (display_id == HWC_DISPLAY_PRIMARY) {
1057 DLOGE("Not supported for this display");
1058 } else if (!hwc_display_[display_id]) {
1059 DLOGW("Display is not connected");
1060 } else {
1061 ret = hwc_display_[display_id]->SetDisplayStatus(display_status);
1062 }
1063
1064 output_parcel->writeInt32(ret);
1065
1066 return ret;
1067 }
1068
ConfigureRefreshRate(const android::Parcel * input_parcel)1069 android::status_t HWCSession::ConfigureRefreshRate(const android::Parcel *input_parcel) {
1070 uint32_t operation = UINT32(input_parcel->readInt32());
1071 switch (operation) {
1072 case qdutils::DISABLE_METADATA_DYN_REFRESH_RATE:
1073 return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
1074 HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
1075 case qdutils::ENABLE_METADATA_DYN_REFRESH_RATE:
1076 return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
1077 HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true);
1078 case qdutils::SET_BINDER_DYN_REFRESH_RATE:
1079 {
1080 uint32_t refresh_rate = UINT32(input_parcel->readInt32());
1081 return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
1082 HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE,
1083 refresh_rate);
1084 }
1085 default:
1086 DLOGW("Invalid operation %d", operation);
1087 return -EINVAL;
1088 }
1089
1090 return 0;
1091 }
1092
SetDisplayMode(const android::Parcel * input_parcel)1093 android::status_t HWCSession::SetDisplayMode(const android::Parcel *input_parcel) {
1094 uint32_t mode = UINT32(input_parcel->readInt32());
1095 return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(HWCDisplayPrimary::SET_DISPLAY_MODE, mode);
1096 }
1097
SetMaxMixerStages(const android::Parcel * input_parcel)1098 android::status_t HWCSession::SetMaxMixerStages(const android::Parcel *input_parcel) {
1099 DisplayError error = kErrorNone;
1100 std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32());
1101 uint32_t max_mixer_stages = UINT32(input_parcel->readInt32());
1102
1103 if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) {
1104 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
1105 error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetMaxMixerStages(max_mixer_stages);
1106 if (error != kErrorNone) {
1107 return -EINVAL;
1108 }
1109 }
1110 }
1111
1112 if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) {
1113 if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
1114 error = hwc_display_[HWC_DISPLAY_EXTERNAL]->SetMaxMixerStages(max_mixer_stages);
1115 if (error != kErrorNone) {
1116 return -EINVAL;
1117 }
1118 }
1119 }
1120
1121 if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) {
1122 if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
1123 error = hwc_display_[HWC_DISPLAY_VIRTUAL]->SetMaxMixerStages(max_mixer_stages);
1124 if (error != kErrorNone) {
1125 return -EINVAL;
1126 }
1127 }
1128 }
1129
1130 return 0;
1131 }
1132
SetDynamicBWForCamera(const android::Parcel * input_parcel,android::Parcel * output_parcel)1133 android::status_t HWCSession::SetDynamicBWForCamera(const android::Parcel *input_parcel,
1134 android::Parcel *output_parcel) {
1135 DisplayError error = kErrorNone;
1136 uint32_t camera_status = UINT32(input_parcel->readInt32());
1137 HWBwModes mode = camera_status > 0 ? kBwCamera : kBwDefault;
1138
1139 // trigger invalidate to apply new bw caps.
1140 AsyncRefresh();
1141
1142 error = core_intf_->SetMaxBandwidthMode(mode);
1143 if (error != kErrorNone) {
1144 return -EINVAL;
1145 }
1146
1147 new_bw_mode_ = true;
1148 need_invalidate_ = true;
1149
1150 return 0;
1151 }
1152
GetBWTransactionStatus(const android::Parcel * input_parcel,android::Parcel * output_parcel)1153 android::status_t HWCSession::GetBWTransactionStatus(const android::Parcel *input_parcel,
1154 android::Parcel *output_parcel) {
1155 bool state = true;
1156
1157 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
1158 if (sync_wait(bw_mode_release_fd_, 0) < 0) {
1159 DLOGI("bw_transaction_release_fd is not yet signalled: err= %s", strerror(errno));
1160 state = false;
1161 }
1162 output_parcel->writeInt32(state);
1163 }
1164
1165 return 0;
1166 }
1167
SetFrameDumpConfig(const android::Parcel * input_parcel)1168 void HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) {
1169 uint32_t frame_dump_count = UINT32(input_parcel->readInt32());
1170 std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32());
1171 uint32_t bit_mask_layer_type = UINT32(input_parcel->readInt32());
1172
1173 if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) {
1174 if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
1175 hwc_display_[HWC_DISPLAY_PRIMARY]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
1176 }
1177 }
1178
1179 if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) {
1180 if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
1181 hwc_display_[HWC_DISPLAY_EXTERNAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
1182 }
1183 }
1184
1185 if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) {
1186 if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
1187 hwc_display_[HWC_DISPLAY_VIRTUAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
1188 }
1189 }
1190 }
1191
SetMixerResolution(const android::Parcel * input_parcel)1192 android::status_t HWCSession::SetMixerResolution(const android::Parcel *input_parcel) {
1193 DisplayError error = kErrorNone;
1194 uint32_t dpy = UINT32(input_parcel->readInt32());
1195
1196 if (dpy != HWC_DISPLAY_PRIMARY) {
1197 DLOGI("Resoulution change not supported for this display %d", dpy);
1198 return -EINVAL;
1199 }
1200
1201 if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
1202 DLOGI("Primary display is not initialized");
1203 return -EINVAL;
1204 }
1205
1206 uint32_t width = UINT32(input_parcel->readInt32());
1207 uint32_t height = UINT32(input_parcel->readInt32());
1208
1209 error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetMixerResolution(width, height);
1210 if (error != kErrorNone) {
1211 return -EINVAL;
1212 }
1213
1214 return 0;
1215 }
1216
GetHdrCapabilities(const android::Parcel * input_parcel,android::Parcel * output_parcel)1217 android::status_t HWCSession::GetHdrCapabilities(const android::Parcel *input_parcel,
1218 android::Parcel *output_parcel) {
1219 uint32_t display_id = UINT32(input_parcel->readInt32());
1220 if (display_id >= HWC_NUM_DISPLAY_TYPES) {
1221 DLOGE("Invalid display id = %d", display_id);
1222 return -EINVAL;
1223 }
1224
1225 if (hwc_display_[display_id] == NULL) {
1226 DLOGW("Display = %d not initialized", display_id);
1227 return -EINVAL;
1228 }
1229
1230 DisplayConfigFixedInfo fixed_info = {};
1231 int ret = hwc_display_[display_id]->GetDisplayFixedConfig(&fixed_info);
1232 if (ret) {
1233 DLOGE("Failed");
1234 return ret;
1235 }
1236
1237 if (!fixed_info.hdr_supported) {
1238 DLOGI("HDR is not supported");
1239 return 0;
1240 }
1241
1242 std::vector<int32_t> supported_hdr_types;
1243 // Only HDR10 supported now, in future add other supported HDR formats(HLG, DolbyVision)
1244 supported_hdr_types.push_back(HAL_HDR_HDR10);
1245
1246 static const float kLuminanceFactor = 10000.0;
1247 // luminance is expressed in the unit of 0.0001 cd/m2, convert it to 1cd/m2.
1248 float max_luminance = FLOAT(fixed_info.max_luminance)/kLuminanceFactor;
1249 float max_average_luminance = FLOAT(fixed_info.average_luminance)/kLuminanceFactor;
1250 float min_luminance = FLOAT(fixed_info.min_luminance)/kLuminanceFactor;
1251
1252 if (output_parcel != nullptr) {
1253 output_parcel->writeInt32Vector(supported_hdr_types);
1254 output_parcel->writeFloat(max_luminance);
1255 output_parcel->writeFloat(max_average_luminance);
1256 output_parcel->writeFloat(min_luminance);
1257 }
1258
1259 return 0;
1260 }
1261
DynamicDebug(const android::Parcel * input_parcel)1262 void HWCSession::DynamicDebug(const android::Parcel *input_parcel) {
1263 int type = input_parcel->readInt32();
1264 bool enable = (input_parcel->readInt32() > 0);
1265 DLOGI("type = %d enable = %d", type, enable);
1266 int verbose_level = input_parcel->readInt32();
1267
1268 switch (type) {
1269 case qService::IQService::DEBUG_ALL:
1270 HWCDebugHandler::DebugAll(enable, verbose_level);
1271 break;
1272
1273 case qService::IQService::DEBUG_MDPCOMP:
1274 HWCDebugHandler::DebugStrategy(enable, verbose_level);
1275 HWCDebugHandler::DebugCompManager(enable, verbose_level);
1276 break;
1277
1278 case qService::IQService::DEBUG_PIPE_LIFECYCLE:
1279 HWCDebugHandler::DebugResources(enable, verbose_level);
1280 break;
1281
1282 case qService::IQService::DEBUG_DRIVER_CONFIG:
1283 HWCDebugHandler::DebugDriverConfig(enable, verbose_level);
1284 break;
1285
1286 case qService::IQService::DEBUG_ROTATOR:
1287 HWCDebugHandler::DebugResources(enable, verbose_level);
1288 HWCDebugHandler::DebugDriverConfig(enable, verbose_level);
1289 HWCDebugHandler::DebugRotator(enable, verbose_level);
1290 break;
1291
1292 case qService::IQService::DEBUG_QDCM:
1293 HWCDebugHandler::DebugQdcm(enable, verbose_level);
1294 break;
1295
1296 default:
1297 DLOGW("type = %d is not supported", type);
1298 }
1299 }
1300
QdcmCMDHandler(const android::Parcel * input_parcel,android::Parcel * output_parcel)1301 android::status_t HWCSession::QdcmCMDHandler(const android::Parcel *input_parcel,
1302 android::Parcel *output_parcel) {
1303 int ret = 0;
1304 int32_t *brightness_value = NULL;
1305 uint32_t display_id(0);
1306 PPPendingParams pending_action;
1307 PPDisplayAPIPayload resp_payload, req_payload;
1308
1309 if (!color_mgr_) {
1310 return -1;
1311 }
1312
1313 pending_action.action = kNoAction;
1314 pending_action.params = NULL;
1315
1316 // Read display_id, payload_size and payload from in_parcel.
1317 ret = HWCColorManager::CreatePayloadFromParcel(*input_parcel, &display_id, &req_payload);
1318 if (!ret) {
1319 if (HWC_DISPLAY_PRIMARY == display_id && hwc_display_[HWC_DISPLAY_PRIMARY])
1320 ret = hwc_display_[HWC_DISPLAY_PRIMARY]->ColorSVCRequestRoute(req_payload,
1321 &resp_payload, &pending_action);
1322
1323 if (HWC_DISPLAY_EXTERNAL == display_id && hwc_display_[HWC_DISPLAY_EXTERNAL])
1324 ret = hwc_display_[HWC_DISPLAY_EXTERNAL]->ColorSVCRequestRoute(req_payload, &resp_payload,
1325 &pending_action);
1326 }
1327
1328 if (ret) {
1329 output_parcel->writeInt32(ret); // first field in out parcel indicates return code.
1330 req_payload.DestroyPayload();
1331 resp_payload.DestroyPayload();
1332 return ret;
1333 }
1334
1335 switch (pending_action.action) {
1336 case kInvalidating:
1337 AsyncRefresh();
1338 break;
1339 case kEnterQDCMMode:
1340 ret = color_mgr_->EnableQDCMMode(true, hwc_display_[HWC_DISPLAY_PRIMARY]);
1341 break;
1342 case kExitQDCMMode:
1343 ret = color_mgr_->EnableQDCMMode(false, hwc_display_[HWC_DISPLAY_PRIMARY]);
1344 break;
1345 case kApplySolidFill:
1346 ret = color_mgr_->SetSolidFill(pending_action.params,
1347 true, hwc_display_[HWC_DISPLAY_PRIMARY]);
1348 AsyncRefresh();
1349 break;
1350 case kDisableSolidFill:
1351 ret = color_mgr_->SetSolidFill(pending_action.params,
1352 false, hwc_display_[HWC_DISPLAY_PRIMARY]);
1353 AsyncRefresh();
1354 break;
1355 case kSetPanelBrightness:
1356 brightness_value = reinterpret_cast<int32_t*>(resp_payload.payload);
1357 if (brightness_value == NULL) {
1358 DLOGE("Brightness value is Null");
1359 return -EINVAL;
1360 }
1361 if (HWC_DISPLAY_PRIMARY == display_id)
1362 ret = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(*brightness_value);
1363 break;
1364 case kEnableFrameCapture:
1365 ret = color_mgr_->SetFrameCapture(pending_action.params,
1366 true, hwc_display_[HWC_DISPLAY_PRIMARY]);
1367 AsyncRefresh();
1368 break;
1369 case kDisableFrameCapture:
1370 ret = color_mgr_->SetFrameCapture(pending_action.params,
1371 false, hwc_display_[HWC_DISPLAY_PRIMARY]);
1372 break;
1373 case kConfigureDetailedEnhancer:
1374 ret = color_mgr_->SetDetailedEnhancer(pending_action.params,
1375 hwc_display_[HWC_DISPLAY_PRIMARY]);
1376 AsyncRefresh();
1377 break;
1378 case kInvalidatingAndkSetPanelBrightness:
1379 brightness_value = reinterpret_cast<int32_t*>(resp_payload.payload);
1380 if (brightness_value == NULL) {
1381 DLOGE("Brightness value is Null");
1382 return -EINVAL;
1383 }
1384 if (HWC_DISPLAY_PRIMARY == display_id)
1385 ret = hwc_display_[HWC_DISPLAY_PRIMARY]->CachePanelBrightness(*brightness_value);
1386 AsyncRefresh();
1387 break;
1388 case kNoAction:
1389 break;
1390 default:
1391 DLOGW("Invalid pending action = %d!", pending_action.action);
1392 break;
1393 }
1394
1395 // for display API getter case, marshall returned params into out_parcel.
1396 output_parcel->writeInt32(ret);
1397 HWCColorManager::MarshallStructIntoParcel(resp_payload, output_parcel);
1398 req_payload.DestroyPayload();
1399 resp_payload.DestroyPayload();
1400
1401 return (ret? -EINVAL : 0);
1402 }
1403
OnMinHdcpEncryptionLevelChange(const android::Parcel * input_parcel,android::Parcel * output_parcel)1404 android::status_t HWCSession::OnMinHdcpEncryptionLevelChange(const android::Parcel *input_parcel,
1405 android::Parcel *output_parcel) {
1406 int ret = -EINVAL;
1407 uint32_t display_id = UINT32(input_parcel->readInt32());
1408 uint32_t min_enc_level = UINT32(input_parcel->readInt32());
1409
1410 DLOGI("Display %d", display_id);
1411
1412 if (display_id >= HWC_NUM_DISPLAY_TYPES) {
1413 DLOGE("Invalid display_id");
1414 } else if (display_id != HWC_DISPLAY_EXTERNAL) {
1415 DLOGE("Not supported for display");
1416 } else if (!hwc_display_[display_id]) {
1417 DLOGW("Display is not connected");
1418 } else {
1419 ret = hwc_display_[display_id]->OnMinHdcpEncryptionLevelChange(min_enc_level);
1420 }
1421
1422 output_parcel->writeInt32(ret);
1423
1424 return ret;
1425 }
1426
HWCUeventThread(void * context)1427 void* HWCSession::HWCUeventThread(void *context) {
1428 if (context) {
1429 return reinterpret_cast<HWCSession *>(context)->HWCUeventThreadHandler();
1430 }
1431
1432 return NULL;
1433 }
1434
HWCUeventThreadHandler()1435 void* HWCSession::HWCUeventThreadHandler() {
1436 static char uevent_data[PAGE_SIZE];
1437 int length = 0;
1438
1439 uevent_locker_.Lock();
1440 prctl(PR_SET_NAME, uevent_thread_name_, 0, 0, 0);
1441 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
1442 if (!uevent_init()) {
1443 DLOGE("Failed to init uevent");
1444 pthread_exit(0);
1445 uevent_locker_.Signal();
1446 uevent_locker_.Unlock();
1447 return NULL;
1448 }
1449
1450 uevent_locker_.Signal();
1451 uevent_locker_.Unlock();
1452
1453 while (!uevent_thread_exit_) {
1454 // keep last 2 zeroes to ensure double 0 termination
1455 length = uevent_next_event(uevent_data, INT32(sizeof(uevent_data)) - 2);
1456
1457 if (strcasestr(HWC_UEVENT_SWITCH_HDMI, uevent_data)) {
1458 DLOGI("Uevent HDMI = %s", uevent_data);
1459 int connected = GetEventValue(uevent_data, length, "SWITCH_STATE=");
1460 if (connected >= 0) {
1461 DLOGI("HDMI = %s", connected ? "connected" : "disconnected");
1462 if (HotPlugHandler(connected) == -1) {
1463 DLOGE("Failed handling Hotplug = %s", connected ? "connected" : "disconnected");
1464 }
1465 }
1466 } else if (strcasestr(HWC_UEVENT_GRAPHICS_FB0, uevent_data)) {
1467 DLOGI("Uevent FB0 = %s", uevent_data);
1468 int panel_reset = GetEventValue(uevent_data, length, "PANEL_ALIVE=");
1469 if (panel_reset == 0) {
1470 if (hwc_procs_) {
1471 reset_panel_ = true;
1472 AsyncRefresh();
1473 } else {
1474 DLOGW("Ignore resetpanel - hwc_proc not registered");
1475 }
1476 }
1477 }
1478 }
1479 pthread_exit(0);
1480
1481 return NULL;
1482 }
1483
GetEventValue(const char * uevent_data,int length,const char * event_info)1484 int HWCSession::GetEventValue(const char *uevent_data, int length, const char *event_info) {
1485 const char *iterator_str = uevent_data;
1486 while (((iterator_str - uevent_data) <= length) && (*iterator_str)) {
1487 const char *pstr = strstr(iterator_str, event_info);
1488 if (pstr != NULL) {
1489 return (atoi(iterator_str + strlen(event_info)));
1490 }
1491 iterator_str += strlen(iterator_str) + 1;
1492 }
1493
1494 return -1;
1495 }
1496
ResetPanel()1497 void HWCSession::ResetPanel() {
1498 int status = -EINVAL;
1499
1500 DLOGI("Powering off primary");
1501 status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(HWC_POWER_MODE_OFF);
1502 if (status) {
1503 DLOGE("power-off on primary failed with error = %d", status);
1504 }
1505
1506 DLOGI("Restoring power mode on primary");
1507 int32_t mode = INT(hwc_display_[HWC_DISPLAY_PRIMARY]->GetLastPowerMode());
1508 status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(mode);
1509 if (status) {
1510 DLOGE("Setting power mode = %d on primary failed with error = %d", mode, status);
1511 }
1512
1513 status = hwc_display_[HWC_DISPLAY_PRIMARY]->EventControl(HWC_EVENT_VSYNC, 1);
1514 if (status) {
1515 DLOGE("enabling vsync failed for primary with error = %d", status);
1516 }
1517
1518 reset_panel_ = false;
1519 }
1520
HotPlugHandler(bool connected)1521 int HWCSession::HotPlugHandler(bool connected) {
1522 int status = 0;
1523 bool notify_hotplug = false;
1524 bool refresh_screen = false;
1525
1526 // To prevent sending events to client while a lock is held, acquire scope locks only within
1527 // below scope so that those get automatically unlocked after the scope ends.
1528 {
1529 SEQUENCE_WAIT_SCOPE_LOCK(locker_);
1530
1531 if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
1532 DLOGE("Primay display is not connected.");
1533 return -1;
1534 }
1535
1536
1537 HWCDisplay *primary_display = hwc_display_[HWC_DISPLAY_PRIMARY];
1538 HWCDisplay *external_display = NULL;
1539 HWCDisplay *null_display = NULL;
1540
1541 if (primary_display->GetDisplayClass() == DISPLAY_CLASS_EXTERNAL) {
1542 external_display = static_cast<HWCDisplayExternal *>(hwc_display_[HWC_DISPLAY_PRIMARY]);
1543 } else if (primary_display->GetDisplayClass() == DISPLAY_CLASS_NULL) {
1544 null_display = static_cast<HWCDisplayNull *>(hwc_display_[HWC_DISPLAY_PRIMARY]);
1545 }
1546
1547 // If primary display connected is a NULL display, then replace it with the external display
1548 if (connected) {
1549 // If we are in HDMI as primary and the primary display just got plugged in
1550 if (is_hdmi_primary_ && null_display) {
1551 uint32_t primary_width, primary_height;
1552 int status = 0;
1553 null_display->GetFrameBufferResolution(&primary_width, &primary_height);
1554 delete null_display;
1555 hwc_display_[HWC_DISPLAY_PRIMARY] = NULL;
1556
1557 // Create external display with a forced framebuffer resolution to that of what the NULL
1558 // display had. This is necessary because SurfaceFlinger does not dynamically update
1559 // framebuffer resolution once it reads it at bootup. So we always have to have the NULL
1560 // display/external display both at the bootup resolution.
1561 status = CreateExternalDisplay(HWC_DISPLAY_PRIMARY, primary_width, primary_height, true);
1562 if (status) {
1563 DLOGE("Could not create external display");
1564 return -1;
1565 }
1566
1567 status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(HWC_POWER_MODE_NORMAL);
1568 if (status) {
1569 DLOGE("power-on on primary failed with error = %d", status);
1570 }
1571
1572 is_hdmi_yuv_ = IsDisplayYUV(HWC_DISPLAY_PRIMARY);
1573
1574 // Next, go ahead and enable vsync on external display. This is expliclity required
1575 // because in HDMI as primary case, SurfaceFlinger may not be aware of underlying
1576 // changing display. and thus may not explicitly enable vsync
1577
1578 status = hwc_display_[HWC_DISPLAY_PRIMARY]->EventControl(HWC_EVENT_VSYNC, true);
1579 if (status) {
1580 DLOGE("Error enabling vsync for HDMI as primary case");
1581 }
1582 // Don't do hotplug notification for HDMI as primary case for now
1583 notify_hotplug = false;
1584 refresh_screen = true;
1585 } else {
1586 if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
1587 DLOGE("HDMI is already connected");
1588 return -1;
1589 }
1590
1591 // Connect external display if virtual display is not connected.
1592 // Else, defer external display connection and process it when virtual display
1593 // tears down; Do not notify SurfaceFlinger since connection is deferred now.
1594 if (!hwc_display_[HWC_DISPLAY_VIRTUAL]) {
1595 status = ConnectDisplay(HWC_DISPLAY_EXTERNAL, NULL);
1596 if (status) {
1597 return status;
1598 }
1599 notify_hotplug = true;
1600 } else {
1601 DLOGI("Virtual display is connected, pending connection");
1602 external_pending_connect_ = true;
1603 }
1604 }
1605 } else {
1606 // Do not return error if external display is not in connected status.
1607 // Due to virtual display concurrency, external display connection might be still pending
1608 // but hdmi got disconnected before pending connection could be processed.
1609
1610 if (is_hdmi_primary_ && external_display) {
1611 uint32_t x_res, y_res;
1612 external_display->GetFrameBufferResolution(&x_res, &y_res);
1613 // Need to manually disable VSYNC as SF is not aware of connect/disconnect cases
1614 // for HDMI as primary
1615 external_display->EventControl(HWC_EVENT_VSYNC, false);
1616 HWCDisplayExternal::Destroy(external_display);
1617
1618 HWCDisplayNull *null_display;
1619
1620 int status = HWCDisplayNull::Create(core_intf_, &hwc_procs_,
1621 reinterpret_cast<HWCDisplay **>(&null_display));
1622
1623 if (status) {
1624 DLOGE("Could not create Null display when primary got disconnected");
1625 return -1;
1626 }
1627
1628 null_display->SetResolution(x_res, y_res);
1629 hwc_display_[HWC_DISPLAY_PRIMARY] = null_display;
1630
1631 // Don't do hotplug notification for HDMI as primary case for now
1632 notify_hotplug = false;
1633 } else {
1634 if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
1635 status = DisconnectDisplay(HWC_DISPLAY_EXTERNAL);
1636 notify_hotplug = true;
1637 }
1638 external_pending_connect_ = false;
1639 }
1640 }
1641 }
1642
1643 if (connected && (notify_hotplug || refresh_screen)) {
1644 // trigger screen refresh to ensure sufficient resources are available to process new
1645 // new display connection.
1646 hwc_procs_->invalidate(hwc_procs_);
1647 uint32_t vsync_period = UINT32(GetVsyncPeriod(HWC_DISPLAY_PRIMARY));
1648 usleep(vsync_period * 2 / 1000);
1649 }
1650 // notify client
1651 if (notify_hotplug) {
1652 hwc_procs_->hotplug(hwc_procs_, HWC_DISPLAY_EXTERNAL, connected);
1653 }
1654
1655 qservice_->onHdmiHotplug(INT(connected));
1656
1657 return 0;
1658 }
1659
HandleSecureDisplaySession(hwc_display_contents_1_t ** displays)1660 void HWCSession::HandleSecureDisplaySession(hwc_display_contents_1_t **displays) {
1661 secure_display_active_ = false;
1662 if (!*displays) {
1663 DLOGW("Invalid display contents");
1664 return;
1665 }
1666
1667 hwc_display_contents_1_t *content_list = displays[HWC_DISPLAY_PRIMARY];
1668 if (!content_list) {
1669 DLOGW("Invalid primary content list");
1670 return;
1671 }
1672 size_t num_hw_layers = content_list->numHwLayers;
1673
1674 for (size_t i = 0; i < num_hw_layers - 1; i++) {
1675 hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
1676 const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer.handle);
1677 if (pvt_handle && pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY) {
1678 secure_display_active_ = true;
1679 }
1680 }
1681
1682 // Force flush on primary during transitions(secure<->non secure)
1683 // when external displays are connected.
1684 bool force_flush = false;
1685 if ((connected_displays_[HWC_DISPLAY_PRIMARY] == 1) &&
1686 ((connected_displays_[HWC_DISPLAY_EXTERNAL] == 1) ||
1687 (connected_displays_[HWC_DISPLAY_VIRTUAL] == 1))) {
1688 force_flush = true;
1689 }
1690
1691 for (ssize_t dpy = static_cast<ssize_t>(HWC_NUM_DISPLAY_TYPES - 1); dpy >= 0; dpy--) {
1692 if (hwc_display_[dpy]) {
1693 hwc_display_[dpy]->SetSecureDisplay(secure_display_active_, force_flush);
1694 }
1695 }
1696 }
1697
GetVisibleDisplayRect(const android::Parcel * input_parcel,android::Parcel * output_parcel)1698 android::status_t HWCSession::GetVisibleDisplayRect(const android::Parcel *input_parcel,
1699 android::Parcel *output_parcel) {
1700 int dpy = input_parcel->readInt32();
1701
1702 if (dpy < HWC_DISPLAY_PRIMARY || dpy > HWC_DISPLAY_VIRTUAL) {
1703 return android::BAD_VALUE;;
1704 }
1705
1706 if (!hwc_display_[dpy]) {
1707 return android::NO_INIT;
1708 }
1709
1710 hwc_rect_t visible_rect = {0, 0, 0, 0};
1711 int error = hwc_display_[dpy]->GetVisibleDisplayRect(&visible_rect);
1712 if (error < 0) {
1713 return error;
1714 }
1715
1716 output_parcel->writeInt32(visible_rect.left);
1717 output_parcel->writeInt32(visible_rect.top);
1718 output_parcel->writeInt32(visible_rect.right);
1719 output_parcel->writeInt32(visible_rect.bottom);
1720
1721 return android::NO_ERROR;
1722 }
1723
CreateExternalDisplay(int disp,uint32_t primary_width,uint32_t primary_height,bool use_primary_res)1724 int HWCSession::CreateExternalDisplay(int disp, uint32_t primary_width, uint32_t primary_height,
1725 bool use_primary_res) {
1726 uint32_t panel_bpp = 0;
1727 uint32_t pattern_type = 0;
1728
1729 if (qdutils::isDPConnected()) {
1730 qdutils::getDPTestConfig(&panel_bpp, &pattern_type);
1731 }
1732
1733 if (panel_bpp && pattern_type) {
1734 return HWCDisplayExternalTest::Create(core_intf_, &hwc_procs_, qservice_, panel_bpp,
1735 pattern_type, &hwc_display_[disp]);
1736 }
1737
1738 return HWCDisplayExternal::Create(core_intf_, &hwc_procs_, primary_width, primary_height,
1739 qservice_, use_primary_res, &hwc_display_[disp]);
1740 }
1741
1742 } // namespace sdm
1743
1744