summaryrefslogtreecommitdiff
path: root/msm8909/sdm/libs/hwc/hwc_session.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'msm8909/sdm/libs/hwc/hwc_session.cpp')
-rw-r--r--msm8909/sdm/libs/hwc/hwc_session.cpp1734
1 files changed, 1734 insertions, 0 deletions
diff --git a/msm8909/sdm/libs/hwc/hwc_session.cpp b/msm8909/sdm/libs/hwc/hwc_session.cpp
new file mode 100644
index 00000000..31594408
--- /dev/null
+++ b/msm8909/sdm/libs/hwc/hwc_session.cpp
@@ -0,0 +1,1734 @@
+/*
+* Copyright (c) 2014 - 2018, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <core/dump_interface.h>
+#include <core/buffer_allocator.h>
+#include <private/color_params.h>
+#include <utils/constants.h>
+#include <utils/String16.h>
+#include <cutils/properties.h>
+#include <hardware_legacy/uevent.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+#include <binder/Parcel.h>
+#include <QService.h>
+#include <gr.h>
+#include <gralloc_priv.h>
+#include <display_config.h>
+#include <utils/debug.h>
+#include <sync/sync.h>
+#include <profiler.h>
+#include <bitset>
+#include <vector>
+
+#include "hwc_buffer_allocator.h"
+#include "hwc_buffer_sync_handler.h"
+#include "hwc_session.h"
+#include "hwc_debugger.h"
+#include "hwc_display_null.h"
+#include "hwc_display_primary.h"
+#include "hwc_display_virtual.h"
+#include "hwc_display_external_test.h"
+#include "qd_utils.h"
+
+#define __CLASS__ "HWCSession"
+
+#define HWC_UEVENT_SWITCH_HDMI "change@/devices/virtual/switch/hdmi"
+#define HWC_UEVENT_GRAPHICS_FB0 "change@/devices/virtual/graphics/fb0"
+
+static sdm::HWCSession::HWCModuleMethods g_hwc_module_methods;
+
+hwc_module_t HAL_MODULE_INFO_SYM = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 2,
+ .version_minor = 0,
+ .id = HWC_HARDWARE_MODULE_ID,
+ .name = "QTI Hardware Composer Module",
+ .author = "CodeAurora Forum",
+ .methods = &g_hwc_module_methods,
+ .dso = 0,
+ .reserved = {0},
+ }
+};
+
+namespace sdm {
+
+Locker HWCSession::locker_;
+
+static void Invalidate(const struct hwc_procs *procs) {
+}
+
+static void VSync(const struct hwc_procs* procs, int disp, int64_t timestamp) {
+}
+
+static void Hotplug(const struct hwc_procs* procs, int disp, int connected) {
+}
+
+HWCSession::HWCSession(const hw_module_t *module) {
+ // By default, drop any events. Calls will be routed to SurfaceFlinger after registerProcs.
+ hwc_procs_default_.invalidate = Invalidate;
+ hwc_procs_default_.vsync = VSync;
+ hwc_procs_default_.hotplug = Hotplug;
+
+ hwc_composer_device_1_t::common.tag = HARDWARE_DEVICE_TAG;
+ hwc_composer_device_1_t::common.version = HWC_DEVICE_API_VERSION_1_5;
+ hwc_composer_device_1_t::common.module = const_cast<hw_module_t*>(module);
+ hwc_composer_device_1_t::common.close = Close;
+ hwc_composer_device_1_t::prepare = Prepare;
+ hwc_composer_device_1_t::set = Set;
+ hwc_composer_device_1_t::eventControl = EventControl;
+ hwc_composer_device_1_t::setPowerMode = SetPowerMode;
+ hwc_composer_device_1_t::query = Query;
+ hwc_composer_device_1_t::registerProcs = RegisterProcs;
+ hwc_composer_device_1_t::dump = Dump;
+ hwc_composer_device_1_t::getDisplayConfigs = GetDisplayConfigs;
+ hwc_composer_device_1_t::getDisplayAttributes = GetDisplayAttributes;
+ hwc_composer_device_1_t::getActiveConfig = GetActiveConfig;
+ hwc_composer_device_1_t::setActiveConfig = SetActiveConfig;
+ hwc_composer_device_1_t::setCursorPositionAsync = SetCursorPositionAsync;
+}
+
+int HWCSession::Init() {
+ int status = -EINVAL;
+ const char *qservice_name = "display.qservice";
+
+ // Start QService and connect to it.
+ qService::QService::init();
+ android::sp<qService::IQService> iqservice = android::interface_cast<qService::IQService>(
+ android::defaultServiceManager()->getService(android::String16(qservice_name)));
+
+ if (iqservice.get()) {
+ iqservice->connect(android::sp<qClient::IQClient>(this));
+ qservice_ = reinterpret_cast<qService::QService* >(iqservice.get());
+ } else {
+ DLOGE("Failed to acquire %s", qservice_name);
+ return -EINVAL;
+ }
+
+ DisplayError error = CoreInterface::CreateCore(HWCDebugHandler::Get(), &buffer_allocator_,
+ &buffer_sync_handler_, &socket_handler_,
+ &core_intf_);
+ if (error != kErrorNone) {
+ DLOGE("Display core initialization failed. Error = %d", error);
+ return -EINVAL;
+ }
+
+ SCOPE_LOCK(uevent_locker_);
+
+ if (pthread_create(&uevent_thread_, NULL, &HWCUeventThread, this) < 0) {
+ DLOGE("Failed to start = %s, error = %s", uevent_thread_name_, strerror(errno));
+ CoreInterface::DestroyCore();
+ return -errno;
+ }
+
+ // Wait for uevent_init() to happen and let the uevent thread wait for uevents, so that hdmi
+ // connect/disconnect events won't be missed
+ uevent_locker_.Wait();
+
+ // Read which display is first, and create it and store it in primary slot
+ HWDisplayInterfaceInfo hw_disp_info;
+ error = core_intf_->GetFirstDisplayInterfaceType(&hw_disp_info);
+ if (error == kErrorNone) {
+ if (hw_disp_info.type == kHDMI) {
+ // HDMI is primary display. If already connected, then create it and store in
+ // primary display slot. If not connected, create a NULL display for now.
+ HWCDebugHandler::Get()->SetProperty("persist.sys.is_hdmi_primary", "1");
+ is_hdmi_primary_ = true;
+ if (hw_disp_info.is_connected) {
+ status = CreateExternalDisplay(HWC_DISPLAY_PRIMARY, 0, 0, false);
+ is_hdmi_yuv_ = IsDisplayYUV(HWC_DISPLAY_PRIMARY);
+ } else {
+ // NullDisplay simply closes all its fences, and advertizes a standard
+ // resolution to SurfaceFlinger
+ status = HWCDisplayNull::Create(core_intf_, &hwc_procs_,
+ &hwc_display_[HWC_DISPLAY_PRIMARY]);
+ }
+ } else {
+ // Create and power on primary display
+ status = HWCDisplayPrimary::Create(core_intf_, &buffer_allocator_, &hwc_procs_, qservice_,
+ &hwc_display_[HWC_DISPLAY_PRIMARY]);
+ }
+ } else {
+ // Create and power on primary display
+ status = HWCDisplayPrimary::Create(core_intf_, &buffer_allocator_, &hwc_procs_, qservice_,
+ &hwc_display_[HWC_DISPLAY_PRIMARY]);
+ }
+
+ if (status) {
+ CoreInterface::DestroyCore();
+ uevent_thread_exit_ = true;
+ pthread_join(uevent_thread_, NULL);
+ return status;
+ }
+
+ color_mgr_ = HWCColorManager::CreateColorManager();
+ if (!color_mgr_) {
+ DLOGW("Failed to load HWCColorManager.");
+ }
+
+ connected_displays_[HWC_DISPLAY_PRIMARY] = 1;
+ struct rlimit fd_limit = {};
+ getrlimit(RLIMIT_NOFILE, &fd_limit);
+ fd_limit.rlim_cur = fd_limit.rlim_cur * 2;
+ auto err = setrlimit(RLIMIT_NOFILE, &fd_limit);
+ if (err) {
+ DLOGW("Unable to increase fd limit - err: %d, %s", errno, strerror(errno));
+ }
+ return 0;
+}
+
+int HWCSession::Deinit() {
+ HWCDisplayPrimary::Destroy(hwc_display_[HWC_DISPLAY_PRIMARY]);
+ hwc_display_[HWC_DISPLAY_PRIMARY] = 0;
+ if (color_mgr_) {
+ color_mgr_->DestroyColorManager();
+ }
+ uevent_thread_exit_ = true;
+ pthread_join(uevent_thread_, NULL);
+
+ DisplayError error = CoreInterface::DestroyCore();
+ if (error != kErrorNone) {
+ DLOGE("Display core de-initialization failed. Error = %d", error);
+ }
+
+ connected_displays_[HWC_DISPLAY_PRIMARY] = 0;
+ return 0;
+}
+
+int HWCSession::Open(const hw_module_t *module, const char *name, hw_device_t **device) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ if (!module || !name || !device) {
+ DLOGE("Invalid parameters.");
+ return -EINVAL;
+ }
+
+ if (!strcmp(name, HWC_HARDWARE_COMPOSER)) {
+ HWCSession *hwc_session = new HWCSession(module);
+ if (!hwc_session) {
+ return -ENOMEM;
+ }
+
+ int status = hwc_session->Init();
+ if (status != 0) {
+ delete hwc_session;
+ return status;
+ }
+
+ hwc_composer_device_1_t *composer_device = hwc_session;
+ *device = reinterpret_cast<hw_device_t *>(composer_device);
+ }
+
+ return 0;
+}
+
+int HWCSession::Close(hw_device_t *device) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ if (!device) {
+ return -EINVAL;
+ }
+
+ hwc_composer_device_1_t *composer_device = reinterpret_cast<hwc_composer_device_1_t *>(device);
+ HWCSession *hwc_session = static_cast<HWCSession *>(composer_device);
+
+ hwc_session->Deinit();
+ delete hwc_session;
+
+ return 0;
+}
+
+int HWCSession::Prepare(hwc_composer_device_1 *device, size_t num_displays,
+ hwc_display_contents_1_t **displays) {
+ DTRACE_SCOPED();
+
+ if (!device || !displays || num_displays > HWC_NUM_DISPLAY_TYPES) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ hwc_procs_t const *hwc_procs = NULL;
+ bool hotplug_connect = false;
+
+ // Hold mutex only in this scope.
+ {
+ SEQUENCE_ENTRY_SCOPE_LOCK(locker_);
+
+ hwc_procs = hwc_session->hwc_procs_;
+
+ if (hwc_session->reset_panel_) {
+ DLOGW("panel is in bad state, resetting the panel");
+ hwc_session->ResetPanel();
+ }
+
+ if (hwc_session->need_invalidate_) {
+ hwc_procs->invalidate(hwc_procs);
+ hwc_session->need_invalidate_ = false;
+ }
+
+ hwc_session->HandleSecureDisplaySession(displays);
+
+ if (hwc_session->color_mgr_) {
+ HWCDisplay *primary_display = hwc_session->hwc_display_[HWC_DISPLAY_PRIMARY];
+ if (primary_display && !hwc_session->is_hdmi_primary_) {
+ int ret = hwc_session->color_mgr_->SolidFillLayersPrepare(displays, primary_display);
+ if (ret)
+ return 0;
+ }
+ }
+
+ for (ssize_t dpy = static_cast<ssize_t>(num_displays - 1); dpy >= 0; dpy--) {
+ hwc_display_contents_1_t *content_list = displays[dpy];
+ // If external display is connected, ignore virtual display content list.
+ // If virtual display content list is valid, connect virtual display if not connected.
+ // If virtual display content list is invalid, disconnect virtual display if connected.
+ // If external display connection is pending, connect external display when virtual
+ // display is destroyed.
+ // If HDMI is primary and the output format is YUV then ignore the virtual display
+ // content list.
+ if (dpy == HWC_DISPLAY_VIRTUAL) {
+ if (hwc_session->hwc_display_[HWC_DISPLAY_EXTERNAL] ||
+ (hwc_session->is_hdmi_primary_ && hwc_session->is_hdmi_yuv_)) {
+ continue;
+ }
+
+ bool valid_content = HWCDisplayVirtual::IsValidContentList(content_list);
+ bool connected = (hwc_session->hwc_display_[HWC_DISPLAY_VIRTUAL] != NULL);
+
+ if (valid_content && !connected) {
+ hwc_session->ConnectDisplay(HWC_DISPLAY_VIRTUAL, content_list);
+ } else if (!valid_content && connected) {
+ hwc_session->DisconnectDisplay(HWC_DISPLAY_VIRTUAL);
+
+ if (hwc_session->external_pending_connect_) {
+ DLOGI("Process pending external display connection");
+ hwc_session->ConnectDisplay(HWC_DISPLAY_EXTERNAL, NULL);
+ hwc_session->external_pending_connect_ = false;
+ hotplug_connect = true;
+ }
+ }
+ }
+
+ if (hwc_session->hwc_display_[dpy]) {
+ if (!content_list) {
+ DLOGI("Display[%d] connected. content_list is null", dpy);
+ } else if (!content_list->numHwLayers) {
+ DLOGE("Display[%d] connected. numHwLayers is zero", dpy);
+ } else {
+ hwc_session->hwc_display_[dpy]->Prepare(content_list);
+ }
+ }
+ }
+ }
+
+ if (hotplug_connect) {
+ // notify client
+ hwc_procs->hotplug(hwc_procs, HWC_DISPLAY_EXTERNAL, true);
+ }
+ // Return 0, else client will go into bad state
+ return 0;
+}
+
+int HWCSession::GetVsyncPeriod(int disp) {
+ SCOPE_LOCK(locker_);
+ // default value
+ int32_t vsync_period = 1000000000l / 60;
+ const uint32_t attribute = HWC_DISPLAY_VSYNC_PERIOD;
+
+ if (hwc_display_[disp]) {
+ hwc_display_[disp]->GetDisplayAttributes(0, &attribute, &vsync_period);
+ }
+
+ return vsync_period;
+}
+
+int HWCSession::Set(hwc_composer_device_1 *device, size_t num_displays,
+ hwc_display_contents_1_t **displays) {
+ DTRACE_SCOPED();
+
+ SEQUENCE_EXIT_SCOPE_LOCK(locker_);
+
+ if (!device || !displays || num_displays > HWC_NUM_DISPLAY_TYPES) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+
+ if (hwc_session->color_mgr_) {
+ HWCDisplay *primary_display = hwc_session->hwc_display_[HWC_DISPLAY_PRIMARY];
+ if (primary_display) {
+ int ret = hwc_session->color_mgr_->SolidFillLayersSet(displays, primary_display);
+ if (ret)
+ return 0;
+ hwc_session->color_mgr_->SetColorModeDetailEnhancer(primary_display);
+ }
+ }
+
+ for (size_t dpy = 0; dpy < num_displays; dpy++) {
+ hwc_display_contents_1_t *content_list = displays[dpy];
+
+ // Drop virtual display composition if virtual display object could not be created
+ // due to HDMI concurrency.
+ if (dpy == HWC_DISPLAY_VIRTUAL && !hwc_session->hwc_display_[HWC_DISPLAY_VIRTUAL]) {
+ CloseAcquireFds(content_list);
+ if (content_list) {
+ content_list->retireFenceFd = -1;
+ }
+
+ continue;
+ }
+
+ if (hwc_session->hwc_display_[dpy]) {
+ hwc_session->hwc_display_[dpy]->Commit(content_list);
+ }
+ CloseAcquireFds(content_list);
+ }
+
+ if (hwc_session->new_bw_mode_) {
+ hwc_display_contents_1_t *content_list = displays[HWC_DISPLAY_PRIMARY];
+ hwc_session->new_bw_mode_ = false;
+ if (hwc_session->bw_mode_release_fd_ >= 0) {
+ close(hwc_session->bw_mode_release_fd_);
+ }
+ hwc_session->bw_mode_release_fd_ = dup(content_list->retireFenceFd);
+ }
+
+ // This is only indicative of how many times SurfaceFlinger posts
+ // frames to the display.
+ CALC_FPS();
+
+ // Return 0, else client will go into bad state
+ return 0;
+}
+
+void HWCSession::CloseAcquireFds(hwc_display_contents_1_t *content_list) {
+ if (content_list) {
+ for (size_t i = 0; i < content_list->numHwLayers; i++) {
+ int &acquireFenceFd = content_list->hwLayers[i].acquireFenceFd;
+ if (acquireFenceFd >= 0) {
+ close(acquireFenceFd);
+ acquireFenceFd = -1;
+ }
+ }
+
+ int &outbufAcquireFenceFd = content_list->outbufAcquireFenceFd;
+ if (outbufAcquireFenceFd >= 0) {
+ close(outbufAcquireFenceFd);
+ outbufAcquireFenceFd = -1;
+ }
+ }
+}
+
+bool HWCSession::IsDisplayYUV(int disp) {
+ int error = -EINVAL;
+ bool is_yuv = false;
+ DisplayConfigVariableInfo attributes = {};
+
+ if (disp < 0 || disp >= HWC_NUM_DISPLAY_TYPES || !hwc_display_[disp]) {
+ DLOGE("Invalid input parameters. Display = %d", disp);
+ return is_yuv;
+ }
+
+ uint32_t active_config = 0;
+ error = hwc_display_[disp]->GetActiveDisplayConfig(&active_config);
+ if (!error) {
+ error = hwc_display_[disp]->GetDisplayAttributesForConfig(INT(active_config), &attributes);
+ if (error == 0) {
+ is_yuv = attributes.is_yuv;
+ } else {
+ DLOGW("Error querying display attributes. Display = %d, Config = %d", disp, active_config);
+ }
+ }
+
+ return is_yuv;
+}
+
+int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event, int enable) {
+ SCOPE_LOCK(locker_);
+
+ if (!device) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ int status = -EINVAL;
+ if (hwc_session->hwc_display_[disp]) {
+ status = hwc_session->hwc_display_[disp]->EventControl(event, enable);
+ }
+
+ return status;
+}
+
+int HWCSession::SetPowerMode(hwc_composer_device_1 *device, int disp, int mode) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ if (!device) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ int status = -EINVAL;
+ if (hwc_session->hwc_display_[disp]) {
+ status = hwc_session->hwc_display_[disp]->SetPowerMode(mode);
+ }
+
+ return status;
+}
+
+int HWCSession::Query(hwc_composer_device_1 *device, int param, int *value) {
+ SCOPE_LOCK(locker_);
+
+ if (!device || !value) {
+ return -EINVAL;
+ }
+
+ int status = 0;
+
+ switch (param) {
+ case HWC_BACKGROUND_LAYER_SUPPORTED:
+ value[0] = 1;
+ break;
+
+ default:
+ status = -EINVAL;
+ }
+
+ return status;
+}
+
+void HWCSession::RegisterProcs(hwc_composer_device_1 *device, hwc_procs_t const *procs) {
+ SCOPE_LOCK(locker_);
+
+ if (!device || !procs) {
+ return;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ hwc_session->hwc_procs_ = procs;
+}
+
+void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ if (!device || !buffer || !length) {
+ return;
+ }
+
+ DumpInterface::GetDump(buffer, UINT32(length));
+}
+
+int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs,
+ size_t *num_configs) {
+ SCOPE_LOCK(locker_);
+
+ if (!device || !configs || !num_configs) {
+ return -EINVAL;
+ }
+
+ if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ int status = -EINVAL;
+ if (hwc_session->hwc_display_[disp]) {
+ status = hwc_session->hwc_display_[disp]->GetDisplayConfigs(configs, num_configs);
+ }
+
+ return status;
+}
+
+int HWCSession::GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
+ const uint32_t *display_attributes, int32_t *values) {
+ SCOPE_LOCK(locker_);
+
+ if (!device || !display_attributes || !values) {
+ return -EINVAL;
+ }
+
+ if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ int status = -EINVAL;
+ if (hwc_session->hwc_display_[disp]) {
+ status = hwc_session->hwc_display_[disp]->GetDisplayAttributes(config, display_attributes,
+ values);
+ }
+
+ return status;
+}
+
+int HWCSession::GetActiveConfig(hwc_composer_device_1 *device, int disp) {
+ SCOPE_LOCK(locker_);
+
+ if (!device) {
+ return -EINVAL;
+ }
+
+ if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ int active_config = -1;
+ if (hwc_session->hwc_display_[disp]) {
+ active_config = hwc_session->hwc_display_[disp]->GetActiveConfig();
+ }
+
+ return active_config;
+}
+
+int HWCSession::SetActiveConfig(hwc_composer_device_1 *device, int disp, int index) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ if (!device) {
+ return -EINVAL;
+ }
+
+ if (disp < HWC_DISPLAY_PRIMARY || disp > HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+ return -EINVAL;
+ }
+
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ int status = -EINVAL;
+
+ if (hwc_session->hwc_display_[disp]) {
+ status = hwc_session->hwc_display_[disp]->SetActiveConfig(index);
+ }
+
+ return status;
+}
+
+int HWCSession::SetCursorPositionAsync(hwc_composer_device_1 *device, int disp, int x, int y) {
+ DTRACE_SCOPED();
+
+ SCOPE_LOCK(locker_);
+
+ if (!device || (disp < HWC_DISPLAY_PRIMARY) || (disp > HWC_DISPLAY_VIRTUAL)) {
+ return -EINVAL;
+ }
+
+ int status = -EINVAL;
+ HWCSession *hwc_session = static_cast<HWCSession *>(device);
+ if (hwc_session->hwc_display_[disp]) {
+ status = hwc_session->hwc_display_[disp]->SetCursorPosition(x, y);
+ }
+
+ return status;
+}
+
+int HWCSession::ConnectDisplay(int disp, hwc_display_contents_1_t *content_list) {
+ DLOGI("Display = %d", disp);
+
+ int status = 0;
+ uint32_t primary_width = 0;
+ uint32_t primary_height = 0;
+
+ hwc_display_[HWC_DISPLAY_PRIMARY]->GetFrameBufferResolution(&primary_width, &primary_height);
+
+ if (disp == HWC_DISPLAY_EXTERNAL) {
+ status = CreateExternalDisplay(disp, primary_width, primary_height, false);
+ connected_displays_[HWC_DISPLAY_EXTERNAL] = 1;
+ } else if (disp == HWC_DISPLAY_VIRTUAL) {
+ status = HWCDisplayVirtual::Create(core_intf_, &hwc_procs_, primary_width, primary_height,
+ content_list, &hwc_display_[disp]);
+ connected_displays_[HWC_DISPLAY_VIRTUAL] = 1;
+ } else {
+ DLOGE("Invalid display type");
+ return -1;
+ }
+
+ if (!status) {
+ hwc_display_[disp]->SetSecureDisplay(secure_display_active_, true);
+ }
+
+ return status;
+}
+
+int HWCSession::DisconnectDisplay(int disp) {
+ DLOGI("Display = %d", disp);
+
+ if (disp == HWC_DISPLAY_EXTERNAL) {
+ HWCDisplayExternal::Destroy(hwc_display_[disp]);
+ connected_displays_[HWC_DISPLAY_EXTERNAL] = 0;
+ } else if (disp == HWC_DISPLAY_VIRTUAL) {
+ HWCDisplayVirtual::Destroy(hwc_display_[disp]);
+ connected_displays_[HWC_DISPLAY_VIRTUAL] = 0;
+ } else {
+ DLOGE("Invalid display type");
+ return -1;
+ }
+
+ hwc_display_[disp] = NULL;
+
+ return 0;
+}
+
+android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ android::status_t status = 0;
+
+ switch (command) {
+ case qService::IQService::DYNAMIC_DEBUG:
+ DynamicDebug(input_parcel);
+ break;
+
+ case qService::IQService::SCREEN_REFRESH:
+ hwc_procs_->invalidate(hwc_procs_);
+ break;
+
+ case qService::IQService::SET_IDLE_TIMEOUT:
+ if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+ uint32_t timeout = UINT32(input_parcel->readInt32());
+ hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(timeout);
+ }
+ break;
+
+ case qService::IQService::SET_FRAME_DUMP_CONFIG:
+ SetFrameDumpConfig(input_parcel);
+ break;
+
+ case qService::IQService::SET_MAX_PIPES_PER_MIXER:
+ status = SetMaxMixerStages(input_parcel);
+ break;
+
+ case qService::IQService::SET_DISPLAY_MODE:
+ status = SetDisplayMode(input_parcel);
+ break;
+
+ case qService::IQService::SET_SECONDARY_DISPLAY_STATUS:
+ status = SetSecondaryDisplayStatus(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::CONFIGURE_DYN_REFRESH_RATE:
+ status = ConfigureRefreshRate(input_parcel);
+ break;
+
+ case qService::IQService::SET_VIEW_FRAME:
+ break;
+
+ case qService::IQService::TOGGLE_SCREEN_UPDATES:
+ status = ToggleScreenUpdates(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::QDCM_SVC_CMDS:
+ status = QdcmCMDHandler(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::MIN_HDCP_ENCRYPTION_LEVEL_CHANGED:
+ status = OnMinHdcpEncryptionLevelChange(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::CONTROL_PARTIAL_UPDATE:
+ status = ControlPartialUpdate(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::SET_ACTIVE_CONFIG:
+ status = HandleSetActiveDisplayConfig(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::GET_ACTIVE_CONFIG:
+ status = HandleGetActiveDisplayConfig(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::GET_CONFIG_COUNT:
+ status = HandleGetDisplayConfigCount(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG:
+ status = HandleGetDisplayAttributesForConfig(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::GET_PANEL_BRIGHTNESS:
+ status = GetPanelBrightness(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::SET_PANEL_BRIGHTNESS:
+ status = SetPanelBrightness(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::GET_DISPLAY_VISIBLE_REGION:
+ status = GetVisibleDisplayRect(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::SET_CAMERA_STATUS:
+ status = SetDynamicBWForCamera(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::GET_BW_TRANSACTION_STATUS:
+ status = GetBWTransactionStatus(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::SET_LAYER_MIXER_RESOLUTION:
+ status = SetMixerResolution(input_parcel);
+ break;
+
+ case qService::IQService::GET_HDR_CAPABILITIES:
+ status = GetHdrCapabilities(input_parcel, output_parcel);
+ break;
+
+ default:
+ DLOGW("QService command = %d is not supported", command);
+ return -EINVAL;
+ }
+
+ return status;
+}
+
+android::status_t HWCSession::ToggleScreenUpdates(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ int input = input_parcel->readInt32();
+ int error = android::BAD_VALUE;
+
+ if (hwc_display_[HWC_DISPLAY_PRIMARY] && (input <= 1) && (input >= 0)) {
+ error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(input == 1);
+ if (error != 0) {
+ DLOGE("Failed to toggle screen updates = %d. Error = %d", input, error);
+ }
+ }
+ output_parcel->writeInt32(error);
+
+ return error;
+}
+
+android::status_t HWCSession::SetPanelBrightness(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ int level = input_parcel->readInt32();
+ int error = android::BAD_VALUE;
+
+ if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+ error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(level);
+ if (error != 0) {
+ DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error);
+ }
+ }
+ output_parcel->writeInt32(error);
+
+ return error;
+}
+
+android::status_t HWCSession::GetPanelBrightness(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ int error = android::BAD_VALUE;
+ int ret = error;
+
+ if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+ error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(&ret);
+ if (error != 0) {
+ ret = error;
+ DLOGE("Failed to get the panel brightness. Error = %d", error);
+ }
+ }
+ output_parcel->writeInt32(ret);
+
+ return error;
+}
+
+android::status_t HWCSession::ControlPartialUpdate(const android::Parcel *input_parcel,
+ android::Parcel *out) {
+ DisplayError error = kErrorNone;
+ int ret = 0;
+ uint32_t disp_id = UINT32(input_parcel->readInt32());
+ uint32_t enable = UINT32(input_parcel->readInt32());
+
+ if (disp_id != HWC_DISPLAY_PRIMARY) {
+ DLOGW("CONTROL_PARTIAL_UPDATE is not applicable for display = %d", disp_id);
+ ret = -EINVAL;
+ out->writeInt32(ret);
+ return ret;
+ }
+
+ if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
+ DLOGE("primary display object is not instantiated");
+ ret = -EINVAL;
+ out->writeInt32(ret);
+ return ret;
+ }
+
+ uint32_t pending = 0;
+ error = hwc_display_[HWC_DISPLAY_PRIMARY]->ControlPartialUpdate(enable, &pending);
+
+ if (error == kErrorNone) {
+ if (!pending) {
+ out->writeInt32(ret);
+ return ret;
+ }
+ } else if (error == kErrorNotSupported) {
+ out->writeInt32(ret);
+ return ret;
+ } else {
+ ret = -EINVAL;
+ out->writeInt32(ret);
+ return ret;
+ }
+
+ // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future.
+ hwc_procs_->invalidate(hwc_procs_);
+
+ // Wait until partial update control is complete
+ ret = locker_.WaitFinite(kPartialUpdateControlTimeoutMs);
+
+ out->writeInt32(ret);
+
+ return ret;
+}
+
+android::status_t HWCSession::HandleSetActiveDisplayConfig(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ int config = input_parcel->readInt32();
+ int dpy = input_parcel->readInt32();
+ int error = android::BAD_VALUE;
+
+ if (dpy > HWC_DISPLAY_VIRTUAL) {
+ return android::BAD_VALUE;
+ }
+
+ if (hwc_display_[dpy]) {
+ error = hwc_display_[dpy]->SetActiveDisplayConfig(config);
+ if (error == 0) {
+ hwc_procs_->invalidate(hwc_procs_);
+ }
+ }
+
+ return error;
+}
+
+android::status_t HWCSession::HandleGetActiveDisplayConfig(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ int dpy = input_parcel->readInt32();
+ int error = android::BAD_VALUE;
+
+ if (dpy > HWC_DISPLAY_VIRTUAL) {
+ return android::BAD_VALUE;
+ }
+
+ if (hwc_display_[dpy]) {
+ uint32_t config = 0;
+ error = hwc_display_[dpy]->GetActiveDisplayConfig(&config);
+ if (error == 0) {
+ output_parcel->writeInt32(INT(config));
+ }
+ }
+
+ return error;
+}
+
+android::status_t HWCSession::HandleGetDisplayConfigCount(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ int dpy = input_parcel->readInt32();
+ int error = android::BAD_VALUE;
+
+ if (dpy > HWC_DISPLAY_VIRTUAL) {
+ return android::BAD_VALUE;
+ }
+
+ uint32_t count = 0;
+ if (hwc_display_[dpy]) {
+ error = hwc_display_[dpy]->GetDisplayConfigCount(&count);
+ if (error == 0) {
+ output_parcel->writeInt32(INT(count));
+ }
+ }
+
+ return error;
+}
+
+android::status_t HWCSession::SetDisplayPort(DisplayPort sdm_disp_port, int *hwc_disp_port) {
+ if (!hwc_disp_port) {
+ return -EINVAL;
+ }
+
+ switch (sdm_disp_port) {
+ case kPortDSI:
+ *hwc_disp_port = qdutils::DISPLAY_PORT_DSI;
+ break;
+ case kPortDTV:
+ *hwc_disp_port = qdutils::DISPLAY_PORT_DTV;
+ break;
+ case kPortLVDS:
+ *hwc_disp_port = qdutils::DISPLAY_PORT_LVDS;
+ break;
+ case kPortEDP:
+ *hwc_disp_port = qdutils::DISPLAY_PORT_EDP;
+ break;
+ case kPortWriteBack:
+ *hwc_disp_port = qdutils::DISPLAY_PORT_WRITEBACK;
+ break;
+ case kPortDP:
+ *hwc_disp_port = qdutils::DISPLAY_PORT_DP;
+ break;
+ case kPortDefault:
+ *hwc_disp_port = qdutils::DISPLAY_PORT_DEFAULT;
+ break;
+ default:
+ DLOGE("Invalid sdm display port %d", sdm_disp_port);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+android::status_t HWCSession::HandleGetDisplayAttributesForConfig(const android::Parcel
+ *input_parcel,
+ android::Parcel *output_parcel) {
+ int config = input_parcel->readInt32();
+ int dpy = input_parcel->readInt32();
+ int error = android::BAD_VALUE;
+ DisplayConfigVariableInfo display_attributes;
+ DisplayPort sdm_disp_port = kPortDefault;
+ int hwc_disp_port = qdutils::DISPLAY_PORT_DEFAULT;
+
+ if (dpy < HWC_DISPLAY_PRIMARY || dpy >= HWC_NUM_DISPLAY_TYPES || config < 0) {
+ return android::BAD_VALUE;
+ }
+
+ if (hwc_display_[dpy]) {
+ error = hwc_display_[dpy]->GetDisplayAttributesForConfig(config, &display_attributes);
+ if (error == 0) {
+ hwc_display_[dpy]->GetDisplayPort(&sdm_disp_port);
+
+ SetDisplayPort(sdm_disp_port, &hwc_disp_port);
+
+ output_parcel->writeInt32(INT(display_attributes.vsync_period_ns));
+ output_parcel->writeInt32(INT(display_attributes.x_pixels));
+ output_parcel->writeInt32(INT(display_attributes.y_pixels));
+ output_parcel->writeFloat(display_attributes.x_dpi);
+ output_parcel->writeFloat(display_attributes.y_dpi);
+ output_parcel->writeInt32(hwc_disp_port);
+ output_parcel->writeInt32(display_attributes.is_yuv);
+ }
+ }
+
+ return error;
+}
+
+android::status_t HWCSession::SetSecondaryDisplayStatus(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ int ret = -EINVAL;
+
+ uint32_t display_id = UINT32(input_parcel->readInt32());
+ uint32_t display_status = UINT32(input_parcel->readInt32());
+
+ DLOGI("Display = %d, Status = %d", display_id, display_status);
+
+ if (display_id >= HWC_NUM_DISPLAY_TYPES) {
+ DLOGE("Invalid display_id");
+ } else if (display_id == HWC_DISPLAY_PRIMARY) {
+ DLOGE("Not supported for this display");
+ } else if (!hwc_display_[display_id]) {
+ DLOGW("Display is not connected");
+ } else {
+ ret = hwc_display_[display_id]->SetDisplayStatus(display_status);
+ }
+
+ output_parcel->writeInt32(ret);
+
+ return ret;
+}
+
+android::status_t HWCSession::ConfigureRefreshRate(const android::Parcel *input_parcel) {
+ uint32_t operation = UINT32(input_parcel->readInt32());
+ switch (operation) {
+ case qdutils::DISABLE_METADATA_DYN_REFRESH_RATE:
+ return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
+ HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
+ case qdutils::ENABLE_METADATA_DYN_REFRESH_RATE:
+ return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
+ HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true);
+ case qdutils::SET_BINDER_DYN_REFRESH_RATE:
+ {
+ uint32_t refresh_rate = UINT32(input_parcel->readInt32());
+ return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(
+ HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE,
+ refresh_rate);
+ }
+ default:
+ DLOGW("Invalid operation %d", operation);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+android::status_t HWCSession::SetDisplayMode(const android::Parcel *input_parcel) {
+ uint32_t mode = UINT32(input_parcel->readInt32());
+ return hwc_display_[HWC_DISPLAY_PRIMARY]->Perform(HWCDisplayPrimary::SET_DISPLAY_MODE, mode);
+}
+
+android::status_t HWCSession::SetMaxMixerStages(const android::Parcel *input_parcel) {
+ DisplayError error = kErrorNone;
+ std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32());
+ uint32_t max_mixer_stages = UINT32(input_parcel->readInt32());
+
+ if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) {
+ if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+ error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetMaxMixerStages(max_mixer_stages);
+ if (error != kErrorNone) {
+ return -EINVAL;
+ }
+ }
+ }
+
+ if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) {
+ if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
+ error = hwc_display_[HWC_DISPLAY_EXTERNAL]->SetMaxMixerStages(max_mixer_stages);
+ if (error != kErrorNone) {
+ return -EINVAL;
+ }
+ }
+ }
+
+ if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) {
+ if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
+ error = hwc_display_[HWC_DISPLAY_VIRTUAL]->SetMaxMixerStages(max_mixer_stages);
+ if (error != kErrorNone) {
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+android::status_t HWCSession::SetDynamicBWForCamera(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ DisplayError error = kErrorNone;
+ uint32_t camera_status = UINT32(input_parcel->readInt32());
+ HWBwModes mode = camera_status > 0 ? kBwCamera : kBwDefault;
+
+ // trigger invalidate to apply new bw caps.
+ hwc_procs_->invalidate(hwc_procs_);
+
+ error = core_intf_->SetMaxBandwidthMode(mode);
+ if (error != kErrorNone) {
+ return -EINVAL;
+ }
+
+ new_bw_mode_ = true;
+ need_invalidate_ = true;
+
+ return 0;
+}
+
+android::status_t HWCSession::GetBWTransactionStatus(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ bool state = true;
+
+ if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+ if (sync_wait(bw_mode_release_fd_, 0) < 0) {
+ DLOGI("bw_transaction_release_fd is not yet signalled: err= %s", strerror(errno));
+ state = false;
+ }
+ output_parcel->writeInt32(state);
+ }
+
+ return 0;
+}
+
+void HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) {
+ uint32_t frame_dump_count = UINT32(input_parcel->readInt32());
+ std::bitset<32> bit_mask_display_type = UINT32(input_parcel->readInt32());
+ uint32_t bit_mask_layer_type = UINT32(input_parcel->readInt32());
+
+ if (bit_mask_display_type[HWC_DISPLAY_PRIMARY]) {
+ if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+ hwc_display_[HWC_DISPLAY_PRIMARY]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
+ }
+ }
+
+ if (bit_mask_display_type[HWC_DISPLAY_EXTERNAL]) {
+ if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
+ hwc_display_[HWC_DISPLAY_EXTERNAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
+ }
+ }
+
+ if (bit_mask_display_type[HWC_DISPLAY_VIRTUAL]) {
+ if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
+ hwc_display_[HWC_DISPLAY_VIRTUAL]->SetFrameDumpConfig(frame_dump_count, bit_mask_layer_type);
+ }
+ }
+}
+
+android::status_t HWCSession::SetMixerResolution(const android::Parcel *input_parcel) {
+ DisplayError error = kErrorNone;
+ uint32_t dpy = UINT32(input_parcel->readInt32());
+
+ if (dpy != HWC_DISPLAY_PRIMARY) {
+ DLOGI("Resoulution change not supported for this display %d", dpy);
+ return -EINVAL;
+ }
+
+ if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
+ DLOGI("Primary display is not initialized");
+ return -EINVAL;
+ }
+
+ uint32_t width = UINT32(input_parcel->readInt32());
+ uint32_t height = UINT32(input_parcel->readInt32());
+
+ error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetMixerResolution(width, height);
+ if (error != kErrorNone) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+android::status_t HWCSession::GetHdrCapabilities(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ uint32_t display_id = UINT32(input_parcel->readInt32());
+ if (display_id >= HWC_NUM_DISPLAY_TYPES) {
+ DLOGE("Invalid display id = %d", display_id);
+ return -EINVAL;
+ }
+
+ if (hwc_display_[display_id] == NULL) {
+ DLOGW("Display = %d not initialized", display_id);
+ return -EINVAL;
+ }
+
+ DisplayConfigFixedInfo fixed_info = {};
+ int ret = hwc_display_[display_id]->GetDisplayFixedConfig(&fixed_info);
+ if (ret) {
+ DLOGE("Failed");
+ return ret;
+ }
+
+ if (!fixed_info.hdr_supported) {
+ DLOGI("HDR is not supported");
+ return 0;
+ }
+
+ std::vector<int32_t> supported_hdr_types;
+ // Only HDR10 supported now, in future add other supported HDR formats(HLG, DolbyVision)
+ supported_hdr_types.push_back(HAL_HDR_HDR10);
+
+ static const float kLuminanceFactor = 10000.0;
+ // luminance is expressed in the unit of 0.0001 cd/m2, convert it to 1cd/m2.
+ float max_luminance = FLOAT(fixed_info.max_luminance)/kLuminanceFactor;
+ float max_average_luminance = FLOAT(fixed_info.average_luminance)/kLuminanceFactor;
+ float min_luminance = FLOAT(fixed_info.min_luminance)/kLuminanceFactor;
+
+ if (output_parcel != nullptr) {
+ output_parcel->writeInt32Vector(supported_hdr_types);
+ output_parcel->writeFloat(max_luminance);
+ output_parcel->writeFloat(max_average_luminance);
+ output_parcel->writeFloat(min_luminance);
+ }
+
+ return 0;
+}
+
+void HWCSession::DynamicDebug(const android::Parcel *input_parcel) {
+ int type = input_parcel->readInt32();
+ bool enable = (input_parcel->readInt32() > 0);
+ DLOGI("type = %d enable = %d", type, enable);
+ int verbose_level = input_parcel->readInt32();
+
+ switch (type) {
+ case qService::IQService::DEBUG_ALL:
+ HWCDebugHandler::DebugAll(enable, verbose_level);
+ break;
+
+ case qService::IQService::DEBUG_MDPCOMP:
+ HWCDebugHandler::DebugStrategy(enable, verbose_level);
+ HWCDebugHandler::DebugCompManager(enable, verbose_level);
+ break;
+
+ case qService::IQService::DEBUG_PIPE_LIFECYCLE:
+ HWCDebugHandler::DebugResources(enable, verbose_level);
+ break;
+
+ case qService::IQService::DEBUG_DRIVER_CONFIG:
+ HWCDebugHandler::DebugDriverConfig(enable, verbose_level);
+ break;
+
+ case qService::IQService::DEBUG_ROTATOR:
+ HWCDebugHandler::DebugResources(enable, verbose_level);
+ HWCDebugHandler::DebugDriverConfig(enable, verbose_level);
+ HWCDebugHandler::DebugRotator(enable, verbose_level);
+ break;
+
+ case qService::IQService::DEBUG_QDCM:
+ HWCDebugHandler::DebugQdcm(enable, verbose_level);
+ break;
+
+ default:
+ DLOGW("type = %d is not supported", type);
+ }
+}
+
+android::status_t HWCSession::QdcmCMDHandler(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ int ret = 0;
+ int32_t *brightness_value = NULL;
+ uint32_t display_id(0);
+ PPPendingParams pending_action;
+ PPDisplayAPIPayload resp_payload, req_payload;
+
+ if (!color_mgr_) {
+ return -1;
+ }
+
+ pending_action.action = kNoAction;
+ pending_action.params = NULL;
+
+ // Read display_id, payload_size and payload from in_parcel.
+ ret = HWCColorManager::CreatePayloadFromParcel(*input_parcel, &display_id, &req_payload);
+ if (!ret) {
+ if (HWC_DISPLAY_PRIMARY == display_id && hwc_display_[HWC_DISPLAY_PRIMARY])
+ ret = hwc_display_[HWC_DISPLAY_PRIMARY]->ColorSVCRequestRoute(req_payload,
+ &resp_payload, &pending_action);
+
+ if (HWC_DISPLAY_EXTERNAL == display_id && hwc_display_[HWC_DISPLAY_EXTERNAL])
+ ret = hwc_display_[HWC_DISPLAY_EXTERNAL]->ColorSVCRequestRoute(req_payload, &resp_payload,
+ &pending_action);
+ }
+
+ if (ret) {
+ output_parcel->writeInt32(ret); // first field in out parcel indicates return code.
+ req_payload.DestroyPayload();
+ resp_payload.DestroyPayload();
+ return ret;
+ }
+
+ switch (pending_action.action) {
+ case kInvalidating:
+ hwc_procs_->invalidate(hwc_procs_);
+ break;
+ case kEnterQDCMMode:
+ ret = color_mgr_->EnableQDCMMode(true, hwc_display_[HWC_DISPLAY_PRIMARY]);
+ break;
+ case kExitQDCMMode:
+ ret = color_mgr_->EnableQDCMMode(false, hwc_display_[HWC_DISPLAY_PRIMARY]);
+ break;
+ case kApplySolidFill:
+ ret = color_mgr_->SetSolidFill(pending_action.params,
+ true, hwc_display_[HWC_DISPLAY_PRIMARY]);
+ hwc_procs_->invalidate(hwc_procs_);
+ break;
+ case kDisableSolidFill:
+ ret = color_mgr_->SetSolidFill(pending_action.params,
+ false, hwc_display_[HWC_DISPLAY_PRIMARY]);
+ hwc_procs_->invalidate(hwc_procs_);
+ break;
+ case kSetPanelBrightness:
+ brightness_value = reinterpret_cast<int32_t*>(resp_payload.payload);
+ if (brightness_value == NULL) {
+ DLOGE("Brightness value is Null");
+ return -EINVAL;
+ }
+ if (HWC_DISPLAY_PRIMARY == display_id)
+ ret = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(*brightness_value);
+ break;
+ case kEnableFrameCapture:
+ ret = color_mgr_->SetFrameCapture(pending_action.params,
+ true, hwc_display_[HWC_DISPLAY_PRIMARY]);
+ hwc_procs_->invalidate(hwc_procs_);
+ break;
+ case kDisableFrameCapture:
+ ret = color_mgr_->SetFrameCapture(pending_action.params,
+ false, hwc_display_[HWC_DISPLAY_PRIMARY]);
+ break;
+ case kConfigureDetailedEnhancer:
+ ret = color_mgr_->SetDetailedEnhancer(pending_action.params,
+ hwc_display_[HWC_DISPLAY_PRIMARY]);
+ hwc_procs_->invalidate(hwc_procs_);
+ break;
+ case kInvalidatingAndkSetPanelBrightness:
+ brightness_value = reinterpret_cast<int32_t*>(resp_payload.payload);
+ if (brightness_value == NULL) {
+ DLOGE("Brightness value is Null");
+ return -EINVAL;
+ }
+ if (HWC_DISPLAY_PRIMARY == display_id)
+ ret = hwc_display_[HWC_DISPLAY_PRIMARY]->CachePanelBrightness(*brightness_value);
+ hwc_procs_->invalidate(hwc_procs_);
+ break;
+ case kNoAction:
+ break;
+ default:
+ DLOGW("Invalid pending action = %d!", pending_action.action);
+ break;
+ }
+
+ // for display API getter case, marshall returned params into out_parcel.
+ output_parcel->writeInt32(ret);
+ HWCColorManager::MarshallStructIntoParcel(resp_payload, output_parcel);
+ req_payload.DestroyPayload();
+ resp_payload.DestroyPayload();
+
+ return (ret? -EINVAL : 0);
+}
+
+android::status_t HWCSession::OnMinHdcpEncryptionLevelChange(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ int ret = -EINVAL;
+ uint32_t display_id = UINT32(input_parcel->readInt32());
+ uint32_t min_enc_level = UINT32(input_parcel->readInt32());
+
+ DLOGI("Display %d", display_id);
+
+ if (display_id >= HWC_NUM_DISPLAY_TYPES) {
+ DLOGE("Invalid display_id");
+ } else if (display_id != HWC_DISPLAY_EXTERNAL) {
+ DLOGE("Not supported for display");
+ } else if (!hwc_display_[display_id]) {
+ DLOGW("Display is not connected");
+ } else {
+ ret = hwc_display_[display_id]->OnMinHdcpEncryptionLevelChange(min_enc_level);
+ }
+
+ output_parcel->writeInt32(ret);
+
+ return ret;
+}
+
+void* HWCSession::HWCUeventThread(void *context) {
+ if (context) {
+ return reinterpret_cast<HWCSession *>(context)->HWCUeventThreadHandler();
+ }
+
+ return NULL;
+}
+
+void* HWCSession::HWCUeventThreadHandler() {
+ static char uevent_data[PAGE_SIZE];
+ int length = 0;
+
+ uevent_locker_.Lock();
+ prctl(PR_SET_NAME, uevent_thread_name_, 0, 0, 0);
+ setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+ if (!uevent_init()) {
+ DLOGE("Failed to init uevent");
+ pthread_exit(0);
+ uevent_locker_.Signal();
+ uevent_locker_.Unlock();
+ return NULL;
+ }
+
+ uevent_locker_.Signal();
+ uevent_locker_.Unlock();
+
+ while (!uevent_thread_exit_) {
+ // keep last 2 zeroes to ensure double 0 termination
+ length = uevent_next_event(uevent_data, INT32(sizeof(uevent_data)) - 2);
+
+ if (strcasestr(HWC_UEVENT_SWITCH_HDMI, uevent_data)) {
+ DLOGI("Uevent HDMI = %s", uevent_data);
+ int connected = GetEventValue(uevent_data, length, "SWITCH_STATE=");
+ if (connected >= 0) {
+ DLOGI("HDMI = %s", connected ? "connected" : "disconnected");
+ if (HotPlugHandler(connected) == -1) {
+ DLOGE("Failed handling Hotplug = %s", connected ? "connected" : "disconnected");
+ }
+ }
+ } else if (strcasestr(HWC_UEVENT_GRAPHICS_FB0, uevent_data)) {
+ DLOGI("Uevent FB0 = %s", uevent_data);
+ int panel_reset = GetEventValue(uevent_data, length, "PANEL_ALIVE=");
+ if (panel_reset == 0) {
+ if (hwc_procs_) {
+ reset_panel_ = true;
+ hwc_procs_->invalidate(hwc_procs_);
+ } else {
+ DLOGW("Ignore resetpanel - hwc_proc not registered");
+ }
+ }
+ }
+ }
+ pthread_exit(0);
+
+ return NULL;
+}
+
+int HWCSession::GetEventValue(const char *uevent_data, int length, const char *event_info) {
+ const char *iterator_str = uevent_data;
+ while (((iterator_str - uevent_data) <= length) && (*iterator_str)) {
+ const char *pstr = strstr(iterator_str, event_info);
+ if (pstr != NULL) {
+ return (atoi(iterator_str + strlen(event_info)));
+ }
+ iterator_str += strlen(iterator_str) + 1;
+ }
+
+ return -1;
+}
+
+void HWCSession::ResetPanel() {
+ int status = -EINVAL;
+
+ DLOGI("Powering off primary");
+ status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(HWC_POWER_MODE_OFF);
+ if (status) {
+ DLOGE("power-off on primary failed with error = %d", status);
+ }
+
+ DLOGI("Restoring power mode on primary");
+ int32_t mode = INT(hwc_display_[HWC_DISPLAY_PRIMARY]->GetLastPowerMode());
+ status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(mode);
+ if (status) {
+ DLOGE("Setting power mode = %d on primary failed with error = %d", mode, status);
+ }
+
+ status = hwc_display_[HWC_DISPLAY_PRIMARY]->EventControl(HWC_EVENT_VSYNC, 1);
+ if (status) {
+ DLOGE("enabling vsync failed for primary with error = %d", status);
+ }
+
+ reset_panel_ = false;
+}
+
+int HWCSession::HotPlugHandler(bool connected) {
+ int status = 0;
+ bool notify_hotplug = false;
+ bool refresh_screen = false;
+
+ // To prevent sending events to client while a lock is held, acquire scope locks only within
+ // below scope so that those get automatically unlocked after the scope ends.
+ {
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+ if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
+ DLOGE("Primay display is not connected.");
+ return -1;
+ }
+
+
+ HWCDisplay *primary_display = hwc_display_[HWC_DISPLAY_PRIMARY];
+ HWCDisplay *external_display = NULL;
+ HWCDisplay *null_display = NULL;
+
+ if (primary_display->GetDisplayClass() == DISPLAY_CLASS_EXTERNAL) {
+ external_display = static_cast<HWCDisplayExternal *>(hwc_display_[HWC_DISPLAY_PRIMARY]);
+ } else if (primary_display->GetDisplayClass() == DISPLAY_CLASS_NULL) {
+ null_display = static_cast<HWCDisplayNull *>(hwc_display_[HWC_DISPLAY_PRIMARY]);
+ }
+
+ // If primary display connected is a NULL display, then replace it with the external display
+ if (connected) {
+ // If we are in HDMI as primary and the primary display just got plugged in
+ if (is_hdmi_primary_ && null_display) {
+ uint32_t primary_width, primary_height;
+ int status = 0;
+ null_display->GetFrameBufferResolution(&primary_width, &primary_height);
+ delete null_display;
+ hwc_display_[HWC_DISPLAY_PRIMARY] = NULL;
+
+ // Create external display with a forced framebuffer resolution to that of what the NULL
+ // display had. This is necessary because SurfaceFlinger does not dynamically update
+ // framebuffer resolution once it reads it at bootup. So we always have to have the NULL
+ // display/external display both at the bootup resolution.
+ status = CreateExternalDisplay(HWC_DISPLAY_PRIMARY, primary_width, primary_height, true);
+ if (status) {
+ DLOGE("Could not create external display");
+ return -1;
+ }
+
+ status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(HWC_POWER_MODE_NORMAL);
+ if (status) {
+ DLOGE("power-on on primary failed with error = %d", status);
+ }
+
+ is_hdmi_yuv_ = IsDisplayYUV(HWC_DISPLAY_PRIMARY);
+
+ // Next, go ahead and enable vsync on external display. This is expliclity required
+ // because in HDMI as primary case, SurfaceFlinger may not be aware of underlying
+ // changing display. and thus may not explicitly enable vsync
+
+ status = hwc_display_[HWC_DISPLAY_PRIMARY]->EventControl(HWC_EVENT_VSYNC, true);
+ if (status) {
+ DLOGE("Error enabling vsync for HDMI as primary case");
+ }
+ // Don't do hotplug notification for HDMI as primary case for now
+ notify_hotplug = false;
+ refresh_screen = true;
+ } else {
+ if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
+ DLOGE("HDMI is already connected");
+ return -1;
+ }
+
+ // Connect external display if virtual display is not connected.
+ // Else, defer external display connection and process it when virtual display
+ // tears down; Do not notify SurfaceFlinger since connection is deferred now.
+ if (!hwc_display_[HWC_DISPLAY_VIRTUAL]) {
+ status = ConnectDisplay(HWC_DISPLAY_EXTERNAL, NULL);
+ if (status) {
+ return status;
+ }
+ notify_hotplug = true;
+ } else {
+ DLOGI("Virtual display is connected, pending connection");
+ external_pending_connect_ = true;
+ }
+ }
+ } else {
+ // Do not return error if external display is not in connected status.
+ // Due to virtual display concurrency, external display connection might be still pending
+ // but hdmi got disconnected before pending connection could be processed.
+
+ if (is_hdmi_primary_ && external_display) {
+ uint32_t x_res, y_res;
+ external_display->GetFrameBufferResolution(&x_res, &y_res);
+ // Need to manually disable VSYNC as SF is not aware of connect/disconnect cases
+ // for HDMI as primary
+ external_display->EventControl(HWC_EVENT_VSYNC, false);
+ HWCDisplayExternal::Destroy(external_display);
+
+ HWCDisplayNull *null_display;
+
+ int status = HWCDisplayNull::Create(core_intf_, &hwc_procs_,
+ reinterpret_cast<HWCDisplay **>(&null_display));
+
+ if (status) {
+ DLOGE("Could not create Null display when primary got disconnected");
+ return -1;
+ }
+
+ null_display->SetResolution(x_res, y_res);
+ hwc_display_[HWC_DISPLAY_PRIMARY] = null_display;
+
+ // Don't do hotplug notification for HDMI as primary case for now
+ notify_hotplug = false;
+ } else {
+ if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
+ status = DisconnectDisplay(HWC_DISPLAY_EXTERNAL);
+ notify_hotplug = true;
+ }
+ external_pending_connect_ = false;
+ }
+ }
+ }
+
+ if (connected && (notify_hotplug || refresh_screen)) {
+ // trigger screen refresh to ensure sufficient resources are available to process new
+ // new display connection.
+ hwc_procs_->invalidate(hwc_procs_);
+ uint32_t vsync_period = UINT32(GetVsyncPeriod(HWC_DISPLAY_PRIMARY));
+ usleep(vsync_period * 2 / 1000);
+ }
+ // notify client
+ if (notify_hotplug) {
+ hwc_procs_->hotplug(hwc_procs_, HWC_DISPLAY_EXTERNAL, connected);
+ }
+
+ qservice_->onHdmiHotplug(INT(connected));
+
+ return 0;
+}
+
+void HWCSession::HandleSecureDisplaySession(hwc_display_contents_1_t **displays) {
+ secure_display_active_ = false;
+ if (!*displays) {
+ DLOGW("Invalid display contents");
+ return;
+ }
+
+ hwc_display_contents_1_t *content_list = displays[HWC_DISPLAY_PRIMARY];
+ if (!content_list) {
+ DLOGW("Invalid primary content list");
+ return;
+ }
+ size_t num_hw_layers = content_list->numHwLayers;
+
+ for (size_t i = 0; i < num_hw_layers - 1; i++) {
+ hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
+ const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer.handle);
+ if (pvt_handle && pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY) {
+ secure_display_active_ = true;
+ }
+ }
+
+ // Force flush on primary during transitions(secure<->non secure)
+ // when external displays are connected.
+ bool force_flush = false;
+ if ((connected_displays_[HWC_DISPLAY_PRIMARY] == 1) &&
+ ((connected_displays_[HWC_DISPLAY_EXTERNAL] == 1) ||
+ (connected_displays_[HWC_DISPLAY_VIRTUAL] == 1))) {
+ force_flush = true;
+ }
+
+ for (ssize_t dpy = static_cast<ssize_t>(HWC_NUM_DISPLAY_TYPES - 1); dpy >= 0; dpy--) {
+ if (hwc_display_[dpy]) {
+ hwc_display_[dpy]->SetSecureDisplay(secure_display_active_, force_flush);
+ }
+ }
+}
+
+android::status_t HWCSession::GetVisibleDisplayRect(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ int dpy = input_parcel->readInt32();
+
+ if (dpy < HWC_DISPLAY_PRIMARY || dpy >= HWC_NUM_DISPLAY_TYPES) {
+ return android::BAD_VALUE;;
+ }
+
+ if (!hwc_display_[dpy]) {
+ return android::NO_INIT;
+ }
+
+ hwc_rect_t visible_rect = {0, 0, 0, 0};
+ int error = hwc_display_[dpy]->GetVisibleDisplayRect(&visible_rect);
+ if (error < 0) {
+ return error;
+ }
+
+ output_parcel->writeInt32(visible_rect.left);
+ output_parcel->writeInt32(visible_rect.top);
+ output_parcel->writeInt32(visible_rect.right);
+ output_parcel->writeInt32(visible_rect.bottom);
+
+ return android::NO_ERROR;
+}
+
+int HWCSession::CreateExternalDisplay(int disp, uint32_t primary_width, uint32_t primary_height,
+ bool use_primary_res) {
+ uint32_t panel_bpp = 0;
+ uint32_t pattern_type = 0;
+
+ if (qdutils::isDPConnected()) {
+ qdutils::getDPTestConfig(&panel_bpp, &pattern_type);
+ }
+
+ if (panel_bpp && pattern_type) {
+ return HWCDisplayExternalTest::Create(core_intf_, &hwc_procs_, qservice_, panel_bpp,
+ pattern_type, &hwc_display_[disp]);
+ }
+
+ return HWCDisplayExternal::Create(core_intf_, &hwc_procs_, primary_width, primary_height,
+ qservice_, use_primary_res, &hwc_display_[disp]);
+}
+
+} // namespace sdm
+