/* * Copyright (c) 2015 - 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hwc_buffer_allocator.h" #include "hwc_buffer_sync_handler.h" #include "hwc_session.h" #include "hwc_debugger.h" #define __CLASS__ "HWCColorManager" namespace sdm { uint32_t HWCColorManager::Get8BitsARGBColorValue(const PPColorFillParams ¶ms) { uint32_t argb_color = ((params.color.r << 16) & 0xff0000) | ((params.color.g << 8) & 0xff00) | ((params.color.b) & 0xff); return argb_color; } int HWCColorManager::CreatePayloadFromParcel(const android::Parcel &in, uint32_t *disp_id, PPDisplayAPIPayload *sink) { int ret = 0; uint32_t id(0); uint32_t size(0); id = UINT32(in.readInt32()); size = UINT32(in.readInt32()); if (size > 0 && size == in.dataAvail()) { const void *data = in.readInplace(size); const uint8_t *temp = reinterpret_cast(data); sink->size = size; sink->payload = const_cast(temp); *disp_id = id; } else { DLOGW("Failing size checking, size = %d", size); ret = -EINVAL; } return ret; } void HWCColorManager::MarshallStructIntoParcel(const PPDisplayAPIPayload &data, android::Parcel *out_parcel) { out_parcel->writeInt32(INT32(data.size)); if (data.payload) out_parcel->write(data.payload, data.size); } HWCColorManager *HWCColorManager::CreateColorManager(HWCBufferAllocator * buffer_allocator) { HWCColorManager *color_mgr = new HWCColorManager(buffer_allocator); if (color_mgr) { // Load display API interface library. And retrieve color API function tables. DynLib &color_apis_lib = color_mgr->color_apis_lib_; if (color_apis_lib.Open(DISPLAY_API_INTERFACE_LIBRARY_NAME)) { if (!color_apis_lib.Sym(DISPLAY_API_FUNC_TABLES, &color_mgr->color_apis_)) { DLOGE("Fail to retrieve = %s from %s", DISPLAY_API_FUNC_TABLES, DISPLAY_API_INTERFACE_LIBRARY_NAME); delete color_mgr; return NULL; } } else { DLOGW("Unable to load = %s", DISPLAY_API_INTERFACE_LIBRARY_NAME); delete color_mgr; return NULL; } DLOGI("Successfully loaded %s", DISPLAY_API_INTERFACE_LIBRARY_NAME); // Load diagclient library and invokes its entry point to pass in display APIs. DynLib &diag_client_lib = color_mgr->diag_client_lib_; if (diag_client_lib.Open(QDCM_DIAG_CLIENT_LIBRARY_NAME)) { if (!diag_client_lib.Sym(INIT_QDCM_DIAG_CLIENT_NAME, reinterpret_cast(&color_mgr->qdcm_diag_init_)) || !diag_client_lib.Sym(DEINIT_QDCM_DIAG_CLIENT_NAME, reinterpret_cast(&color_mgr->qdcm_diag_deinit_))) { DLOGE("Fail to retrieve = %s from %s", INIT_QDCM_DIAG_CLIENT_NAME, QDCM_DIAG_CLIENT_LIBRARY_NAME); } else { // invoke Diag Client entry point to initialize. color_mgr->qdcm_diag_init_(color_mgr->color_apis_); DLOGI("Successfully loaded %s and %s and diag_init'ed", DISPLAY_API_INTERFACE_LIBRARY_NAME, QDCM_DIAG_CLIENT_LIBRARY_NAME); } } else { DLOGW("Unable to load = %s", QDCM_DIAG_CLIENT_LIBRARY_NAME); // only QDCM Diag client failed to be loaded and system still should function. } } else { DLOGE("Unable to create HWCColorManager"); return NULL; } return color_mgr; } HWCColorManager::HWCColorManager(HWCBufferAllocator *buffer_allocator) : buffer_allocator_(buffer_allocator) { } HWCColorManager::~HWCColorManager() { } void HWCColorManager::DestroyColorManager() { if (qdcm_mode_mgr_) { delete qdcm_mode_mgr_; } if (qdcm_diag_deinit_) { qdcm_diag_deinit_(); } delete this; } int HWCColorManager::EnableQDCMMode(bool enable, HWCDisplay *hwc_display) { int ret = 0; if (!qdcm_mode_mgr_) { qdcm_mode_mgr_ = HWCQDCMModeManager::CreateQDCMModeMgr(); if (!qdcm_mode_mgr_) { DLOGE("Unable to create QDCM operating mode manager."); ret = -EFAULT; } } if (qdcm_mode_mgr_) { ret = qdcm_mode_mgr_->EnableQDCMMode(enable, hwc_display); } return ret; } int HWCColorManager::SetSolidFill(const void *params, bool enable, HWCDisplay *hwc_display) { SCOPE_LOCK(locker_); LayerSolidFill solid_fill_color; if (params) { solid_fill_params_ = *reinterpret_cast(params); } else { solid_fill_params_ = PPColorFillParams(); } if (solid_fill_params_.color.r_bitdepth != solid_fill_params_.color.b_bitdepth || solid_fill_params_.color.r_bitdepth != solid_fill_params_.color.g_bitdepth) { DLOGE("invalid bit depth r %d g %d b %d", solid_fill_params_.color.r_bitdepth, solid_fill_params_.color.g_bitdepth, solid_fill_params_.color.b_bitdepth); return -EINVAL; } solid_fill_color.bit_depth = solid_fill_params_.color.r_bitdepth; solid_fill_color.red = solid_fill_params_.color.r; solid_fill_color.blue = solid_fill_params_.color.b; solid_fill_color.green = solid_fill_params_.color.g; solid_fill_color.alpha = 0x3ff; if (enable) { LayerRect solid_fill_rect = { FLOAT(solid_fill_params_.rect.x), FLOAT(solid_fill_params_.rect.y), FLOAT(solid_fill_params_.rect.x) + FLOAT(solid_fill_params_.rect.width), FLOAT(solid_fill_params_.rect.y) + FLOAT(solid_fill_params_.rect.height), }; hwc_display->Perform(HWCDisplayPrimary::SET_QDCM_SOLID_FILL_INFO, &solid_fill_color); hwc_display->Perform(HWCDisplayPrimary::SET_QDCM_SOLID_FILL_RECT, &solid_fill_rect); } else { solid_fill_color.red = 0; solid_fill_color.blue = 0; solid_fill_color.green = 0; solid_fill_color.alpha = 0; hwc_display->Perform(HWCDisplayPrimary::UNSET_QDCM_SOLID_FILL_INFO, &solid_fill_color); } return 0; } int HWCColorManager::SetFrameCapture(void *params, bool enable, HWCDisplay *hwc_display) { SCOPE_LOCK(locker_); int ret = 0; PPFrameCaptureData *frame_capture_data = reinterpret_cast(params); if (enable) { std::memset(&buffer_info, 0x00, sizeof(buffer_info)); hwc_display->GetPanelResolution(&buffer_info.buffer_config.width, &buffer_info.buffer_config.height); if (frame_capture_data->input_params.out_pix_format == PP_PIXEL_FORMAT_RGB_888) { buffer_info.buffer_config.format = kFormatRGB888; } else if (frame_capture_data->input_params.out_pix_format == PP_PIXEL_FORMAT_RGB_2101010) { buffer_info.buffer_config.format = kFormatRGBA1010102; } else { DLOGE("Pixel-format: %d NOT support.", frame_capture_data->input_params.out_pix_format); return -EFAULT; } buffer_info.buffer_config.buffer_count = 1; buffer_info.alloc_buffer_info.fd = -1; buffer_info.alloc_buffer_info.stride = 0; buffer_info.alloc_buffer_info.size = 0; ret = buffer_allocator_->AllocateBuffer(&buffer_info); if (ret != 0) { DLOGE("Buffer allocation failed. ret: %d", ret); return -ENOMEM; } else { void *buffer = mmap(NULL, buffer_info.alloc_buffer_info.size, PROT_READ | PROT_WRITE, MAP_SHARED, buffer_info.alloc_buffer_info.fd, 0); if (buffer == MAP_FAILED) { DLOGE("mmap failed. err = %d", errno); frame_capture_data->buffer = NULL; ret = buffer_allocator_->FreeBuffer(&buffer_info); return -EFAULT; } else { frame_capture_data->buffer = reinterpret_cast(buffer); frame_capture_data->buffer_stride = buffer_info.alloc_buffer_info.stride; frame_capture_data->buffer_size = buffer_info.alloc_buffer_info.size; } ret = hwc_display->FrameCaptureAsync(buffer_info, 1); if (ret < 0) { DLOGE("FrameCaptureAsync failed. ret = %d", ret); } } } else { ret = -EAGAIN; int fence_fd = -1; if (hwc_display->GetFrameCaptureFence(&fence_fd) && (fence_fd >= 0)) { ret = sync_wait(fence_fd, 1000); ::close(fence_fd); } if (!ret) { if (frame_capture_data->buffer != NULL) { if (munmap(frame_capture_data->buffer, buffer_info.alloc_buffer_info.size) != 0) { DLOGE("munmap failed. err = %d", errno); } } if (buffer_allocator_ != NULL) { std::memset(frame_capture_data, 0x00, sizeof(PPFrameCaptureData)); ret = buffer_allocator_->FreeBuffer(&buffer_info); if (ret != 0) { DLOGE("FreeBuffer failed. ret = %d", ret); } } } else { DLOGE("GetFrameCaptureFence failed. ret = %d", ret); } } return ret; } int HWCColorManager::SetHWDetailedEnhancerConfig(void *params, HWCDisplay *hwc_display) { int err = -1; DisplayDetailEnhancerData de_data; PPDETuningCfgData *de_tuning_cfg_data = reinterpret_cast(params); if (de_tuning_cfg_data->cfg_pending == true) { if (!de_tuning_cfg_data->cfg_en) { de_data.enable = 0; } else { de_data.override_flags = kOverrideDEEnable; de_data.enable = 1; if (de_tuning_cfg_data->params.flags & kDeTuningFlagSharpFactor) { de_data.override_flags |= kOverrideDESharpen1; de_data.sharp_factor = de_tuning_cfg_data->params.sharp_factor; } if (de_tuning_cfg_data->params.flags & kDeTuningFlagClip) { de_data.override_flags |= kOverrideDEClip; de_data.clip = de_tuning_cfg_data->params.clip; } if (de_tuning_cfg_data->params.flags & kDeTuningFlagThrQuiet) { de_data.override_flags |= kOverrideDEThrQuiet; de_data.thr_quiet = de_tuning_cfg_data->params.thr_quiet; } if (de_tuning_cfg_data->params.flags & kDeTuningFlagThrDieout) { de_data.override_flags |= kOverrideDEThrDieout; de_data.thr_dieout = de_tuning_cfg_data->params.thr_dieout; } if (de_tuning_cfg_data->params.flags & kDeTuningFlagThrLow) { de_data.override_flags |= kOverrideDEThrLow; de_data.thr_low = de_tuning_cfg_data->params.thr_low; } if (de_tuning_cfg_data->params.flags & kDeTuningFlagThrHigh) { de_data.override_flags |= kOverrideDEThrHigh; de_data.thr_high = de_tuning_cfg_data->params.thr_high; } if (de_tuning_cfg_data->params.flags & kDeTuningFlagContentQualLevel) { switch (de_tuning_cfg_data->params.quality) { case kDeContentQualLow: de_data.quality_level = kContentQualityLow; break; case kDeContentQualMedium: de_data.quality_level = kContentQualityMedium; break; case kDeContentQualHigh: de_data.quality_level = kContentQualityHigh; break; case kDeContentQualUnknown: default: de_data.quality_level = kContentQualityUnknown; break; } } } err = hwc_display->SetDetailEnhancerConfig(de_data); if (err) { DLOGW("SetDetailEnhancerConfig failed. err = %d", err); } de_tuning_cfg_data->cfg_pending = false; } return err; } void HWCColorManager::SetColorModeDetailEnhancer(HWCDisplay *hwc_display) { SCOPE_LOCK(locker_); int err = -1; PPPendingParams pending_action; PPDisplayAPIPayload req_payload; pending_action.action = kGetDetailedEnhancerData; pending_action.params = NULL; if (hwc_display) { err = hwc_display->ColorSVCRequestRoute(req_payload, NULL, &pending_action); if (!err && pending_action.action == kConfigureDetailedEnhancer) { err = SetHWDetailedEnhancerConfig(pending_action.params, hwc_display); } } return; } int HWCColorManager::SetDetailedEnhancer(void *params, HWCDisplay *hwc_display) { SCOPE_LOCK(locker_); int err = -1; err = SetHWDetailedEnhancerConfig(params, hwc_display); return err; } const HWCQDCMModeManager::ActiveFeatureCMD HWCQDCMModeManager::kActiveFeatureCMD[] = { HWCQDCMModeManager::ActiveFeatureCMD("cabl:on", "cabl:off", "cabl:status", "running"), HWCQDCMModeManager::ActiveFeatureCMD("ad:on", "ad:off", "ad:query:status", "running"), HWCQDCMModeManager::ActiveFeatureCMD("svi:on", "svi:off", "svi:status", "running"), }; const char *const HWCQDCMModeManager::kSocketName = "pps"; const char *const HWCQDCMModeManager::kTagName = "surfaceflinger"; const char *const HWCQDCMModeManager::kPackageName = "colormanager"; HWCQDCMModeManager *HWCQDCMModeManager::CreateQDCMModeMgr() { HWCQDCMModeManager *mode_mgr = new HWCQDCMModeManager(); if (!mode_mgr) { DLOGW("No memory to create HWCQDCMModeManager."); return NULL; } else { mode_mgr->socket_fd_ = ::socket_local_client(kSocketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); if (mode_mgr->socket_fd_ < 0) { // it should not be disastrous and we still can grab wakelock in QDCM mode. DLOGW("Unable to connect to dpps socket!"); } // retrieve system GPU idle timeout value for later to recover. mode_mgr->entry_timeout_ = UINT32(HWCDebugHandler::GetIdleTimeoutMs()); } return mode_mgr; } HWCQDCMModeManager::~HWCQDCMModeManager() { if (socket_fd_ >= 0) ::close(socket_fd_); } int HWCQDCMModeManager::EnableActiveFeatures(bool enable, const HWCQDCMModeManager::ActiveFeatureCMD &cmds, bool *was_running) { int ret = 0; ssize_t size = 0; char response[kSocketCMDMaxLength] = { 0, }; if (socket_fd_ < 0) { DLOGW("No socket connection available - assuming dpps is not enabled"); return 0; } if (!enable) { // if client requesting to disable it. // query CABL status, if off, no action. keep the status. size = ::write(socket_fd_, cmds.cmd_query_status, strlen(cmds.cmd_query_status)); if (size < 0) { DLOGW("Unable to send data over socket %s", ::strerror(errno)); ret = -EFAULT; } else { size = ::read(socket_fd_, response, kSocketCMDMaxLength); if (size < 0) { DLOGW("Unable to read data over socket %s", ::strerror(errno)); ret = -EFAULT; } else if (!strncmp(response, cmds.running, strlen(cmds.running))) { *was_running = true; } } if (*was_running) { // if was running, it's requested to disable it. size = ::write(socket_fd_, cmds.cmd_off, strlen(cmds.cmd_off)); if (size < 0) { DLOGW("Unable to send data over socket %s", ::strerror(errno)); ret = -EFAULT; } } } else { // if was running, need enable it back. if (*was_running) { size = ::write(socket_fd_, cmds.cmd_on, strlen(cmds.cmd_on)); if (size < 0) { DLOGW("Unable to send data over socket %s", ::strerror(errno)); ret = -EFAULT; } } } return ret; } int HWCQDCMModeManager::EnableQDCMMode(bool enable, HWCDisplay *hwc_display) { int ret = 0; ret = EnableActiveFeatures((enable ? false : true), kActiveFeatureCMD[kCABLFeature], &cabl_was_running_); // if enter QDCM mode, disable GPU fallback idle timeout. if (hwc_display) { uint32_t timeout = enable ? 0 : entry_timeout_; hwc_display->SetIdleTimeoutMs(timeout); } return ret; } } // namespace sdm