| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "ExynosHWCService.h" |
| |
| #include <chrono> |
| |
| #include "ExynosExternalDisplay.h" |
| #include "ExynosVirtualDisplay.h" |
| #include "ExynosVirtualDisplayModule.h" |
| #define HWC_SERVICE_DEBUG 0 |
| |
| namespace android { |
| |
| ANDROID_SINGLETON_STATIC_INSTANCE(ExynosHWCService); |
| |
| ExynosHWCService::ExynosHWCService() : |
| mHWCService(NULL), |
| mHWCCtx(NULL), |
| bootFinishedCallback(NULL), |
| doPSRExit(NULL) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "ExynosHWCService Constructor is called"); |
| } |
| |
| ExynosHWCService::~ExynosHWCService() |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "ExynosHWCService Destructor is called"); |
| } |
| |
| int ExynosHWCService::addVirtualDisplayDevice() |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s", __func__); |
| |
| mHWCCtx->device->mNumVirtualDisplay++; |
| |
| return NO_ERROR; |
| } |
| |
| int ExynosHWCService::destroyVirtualDisplayDevice() |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s", __func__); |
| |
| mHWCCtx->device->mNumVirtualDisplay--; |
| |
| return NO_ERROR; |
| } |
| |
| int ExynosHWCService::setWFDMode(unsigned int mode) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s::mode=%d", __func__, mode); |
| for (uint32_t i = 0; i < mHWCCtx->device->mDisplays.size(); i++) { |
| if (mHWCCtx->device->mDisplays[i]->mType == HWC_DISPLAY_VIRTUAL) { |
| ExynosVirtualDisplay *virtualdisplay = |
| (ExynosVirtualDisplay *)mHWCCtx->device->mDisplays[i]; |
| return virtualdisplay->setWFDMode(mode); |
| } |
| } |
| return INVALID_OPERATION; |
| } |
| |
| int ExynosHWCService::getWFDMode() |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s", __func__); |
| for (uint32_t i = 0; i < mHWCCtx->device->mDisplays.size(); i++) { |
| if (mHWCCtx->device->mDisplays[i]->mType == HWC_DISPLAY_VIRTUAL) { |
| ExynosVirtualDisplay *virtualdisplay = |
| (ExynosVirtualDisplay *)mHWCCtx->device->mDisplays[i]; |
| return virtualdisplay->getWFDMode(); |
| } |
| } |
| return INVALID_OPERATION; |
| } |
| |
| int ExynosHWCService::sendWFDCommand(int32_t cmd, int32_t ext1, int32_t ext2) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s::cmd=%d, ext1=%d, ext2=%d", __func__, cmd, ext1, ext2); |
| for (uint32_t i = 0; i < mHWCCtx->device->mDisplays.size(); i++) { |
| if (mHWCCtx->device->mDisplays[i]->mType == HWC_DISPLAY_VIRTUAL) { |
| ExynosVirtualDisplay *virtualdisplay = |
| (ExynosVirtualDisplay *)mHWCCtx->device->mDisplays[i]; |
| return virtualdisplay->sendWFDCommand(cmd, ext1, ext2); |
| } |
| } |
| return INVALID_OPERATION; |
| } |
| |
| int ExynosHWCService::setSecureVDSMode(unsigned int mode) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s::mode=%d", __func__, mode); |
| for (uint32_t i = 0; i < mHWCCtx->device->mDisplays.size(); i++) { |
| if (mHWCCtx->device->mDisplays[i]->mType == HWC_DISPLAY_VIRTUAL) { |
| ExynosVirtualDisplay *virtualdisplay = |
| (ExynosVirtualDisplay *)mHWCCtx->device->mDisplays[i]; |
| return virtualdisplay->setSecureVDSMode(mode); |
| } |
| } |
| return INVALID_OPERATION; |
| } |
| |
| int ExynosHWCService::setWFDOutputResolution(unsigned int width, unsigned int height) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s::width=%d, height=%d", __func__, width, height); |
| |
| for (uint32_t i = 0; i < mHWCCtx->device->mDisplays.size(); i++) { |
| if (mHWCCtx->device->mDisplays[i]->mType == HWC_DISPLAY_VIRTUAL) { |
| ExynosVirtualDisplay *virtualdisplay = |
| (ExynosVirtualDisplay *)mHWCCtx->device->mDisplays[i]; |
| return virtualdisplay->setWFDOutputResolution(width, height); |
| } |
| } |
| return INVALID_OPERATION; |
| } |
| |
| void ExynosHWCService::getWFDOutputResolution(unsigned int *width, unsigned int *height) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s", __func__); |
| for (uint32_t i = 0; i < mHWCCtx->device->mDisplays.size(); i++) { |
| if (mHWCCtx->device->mDisplays[i]->mType == HWC_DISPLAY_VIRTUAL) { |
| ExynosVirtualDisplay *virtualdisplay = |
| (ExynosVirtualDisplay *)mHWCCtx->device->mDisplays[i]; |
| virtualdisplay->getWFDOutputResolution(width, height); |
| return; |
| } |
| } |
| } |
| |
| void ExynosHWCService::setPresentationMode(bool use) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s::PresentationMode=%s", __func__, use == false ? "false" : "true"); |
| for (uint32_t i = 0; i < mHWCCtx->device->mDisplays.size(); i++) { |
| if (mHWCCtx->device->mDisplays[i]->mType == HWC_DISPLAY_VIRTUAL) { |
| ExynosVirtualDisplay *virtualdisplay = |
| (ExynosVirtualDisplay *)mHWCCtx->device->mDisplays[i]; |
| virtualdisplay->setPresentationMode(!!use); |
| return; |
| } |
| } |
| } |
| |
| int ExynosHWCService::getPresentationMode() |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s", __func__); |
| for (uint32_t i = 0; i < mHWCCtx->device->mDisplays.size(); i++) { |
| if (mHWCCtx->device->mDisplays[i]->mType == HWC_DISPLAY_VIRTUAL) { |
| ExynosVirtualDisplay *virtualdisplay = |
| (ExynosVirtualDisplay *)mHWCCtx->device->mDisplays[i]; |
| return virtualdisplay->getPresentationMode(); |
| } |
| } |
| return INVALID_OPERATION; |
| } |
| |
| int ExynosHWCService::setVDSGlesFormat(int format) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s::format=%d", __func__, format); |
| |
| for (uint32_t i = 0; i < mHWCCtx->device->mDisplays.size(); i++) { |
| if (mHWCCtx->device->mDisplays[i]->mType == HWC_DISPLAY_VIRTUAL) { |
| ExynosVirtualDisplay *virtualdisplay = |
| (ExynosVirtualDisplay *)mHWCCtx->device->mDisplays[i]; |
| return virtualdisplay->setVDSGlesFormat(format); |
| } |
| } |
| |
| return INVALID_OPERATION; |
| } |
| |
| int ExynosHWCService::getExternalDisplayConfigs() |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s", __func__); |
| |
| ExynosExternalDisplay *external_display = |
| (ExynosExternalDisplay *)mHWCCtx->device->getDisplay(getDisplayId(HWC_DISPLAY_EXTERNAL, 0)); |
| |
| if ((external_display != nullptr) && |
| (external_display->mHpdStatus == true)) { |
| external_display->mDisplayInterface->dumpDisplayConfigs(); |
| } |
| |
| return NO_ERROR; |
| } |
| |
| int ExynosHWCService::setExternalDisplayConfig(unsigned int index) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s::config=%d", __func__, index); |
| |
| ExynosExternalDisplay *external_display = |
| (ExynosExternalDisplay *)mHWCCtx->device->getDisplay(getDisplayId(HWC_DISPLAY_EXTERNAL, 0)); |
| |
| if ((external_display != nullptr) && |
| (external_display->mHpdStatus == true)) { |
| external_display->setActiveConfig(index); |
| } |
| |
| return NO_ERROR; |
| } |
| |
| int ExynosHWCService::setExternalVsyncEnabled(unsigned int index) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s::config=%d", __func__, index); |
| |
| mHWCCtx->device->mVsyncDisplayId = index; |
| ExynosExternalDisplay *external_display = |
| (ExynosExternalDisplay *)mHWCCtx->device->getDisplay(getDisplayId(HWC_DISPLAY_EXTERNAL, 0)); |
| if (external_display != nullptr) |
| external_display->setVsyncEnabled(index); |
| |
| return NO_ERROR; |
| } |
| |
| int ExynosHWCService::getExternalHdrCapabilities() |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s", __func__); |
| |
| ExynosExternalDisplay *external_display = |
| (ExynosExternalDisplay *)mHWCCtx->device->getDisplay(getDisplayId(HWC_DISPLAY_EXTERNAL, 0)); |
| |
| if (external_display != nullptr) |
| return external_display->mExternalHdrSupported; |
| return 0; |
| } |
| |
| void ExynosHWCService::setBootFinishedCallback(void (*callback)(ExynosHWCCtx *)) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s, callback %p", __func__, callback); |
| bootFinishedCallback = callback; |
| } |
| |
| void ExynosHWCService::setBootFinished() { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s", __func__); |
| if (bootFinishedCallback != NULL) |
| bootFinishedCallback(mHWCCtx); |
| } |
| |
| void ExynosHWCService::enableMPP(uint32_t physicalType, uint32_t physicalIndex, uint32_t logicalIndex, uint32_t enable) |
| { |
| ALOGD("%s:: type(%d), index(%d, %d), enable(%d)", |
| __func__, physicalType, physicalIndex, logicalIndex, enable); |
| ExynosResourceManager::enableMPP(physicalType, physicalIndex, logicalIndex, enable); |
| mHWCCtx->device->setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); |
| mHWCCtx->device->onRefresh(); |
| } |
| |
| void ExynosHWCService::setScaleDownRatio(uint32_t physicalType, |
| uint32_t physicalIndex, uint32_t logicalIndex, uint32_t scaleDownRatio) |
| { |
| ALOGD("%s:: type(%d), index(%d, %d), scaleDownRatio(%d)", |
| __func__, physicalType, physicalIndex, logicalIndex, scaleDownRatio); |
| ExynosResourceManager::setScaleDownRatio(physicalType, physicalIndex, logicalIndex, scaleDownRatio); |
| mHWCCtx->device->setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); |
| mHWCCtx->device->onRefresh(); |
| } |
| |
| void ExynosHWCService::setLbeCtrl(uint32_t display_id, uint32_t state, uint32_t lux) { |
| ALOGD("%s:: display_id(%d), state(%d), lux(%d)", __func__, display_id, state, lux); |
| if (mHWCCtx) { |
| auto display = mHWCCtx->device->getDisplay(display_id); |
| |
| if (display != nullptr) { |
| display->setLbeState(static_cast<LbeState>(state)); |
| display->setLbeAmbientLight(lux); |
| } |
| } |
| } |
| |
| void ExynosHWCService::setHWCDebug(int debug) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s, debug %d", __func__, debug); |
| mHWCCtx->device->setHWCDebug(debug); |
| } |
| |
| uint32_t ExynosHWCService::getHWCDebug() |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s", __func__); |
| return mHWCCtx->device->getHWCDebug(); |
| } |
| |
| void ExynosHWCService::setHWCFenceDebug(uint32_t fenceNum, uint32_t ipNum, uint32_t mode) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s", __func__); |
| mHWCCtx->device->setHWCFenceDebug(fenceNum, ipNum, mode); |
| } |
| |
| void ExynosHWCService::getHWCFenceDebug() |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s", __func__); |
| mHWCCtx->device->getHWCFenceDebug(); |
| } |
| |
| int ExynosHWCService::setHWCCtl(uint32_t display, uint32_t ctrl, int32_t val) |
| { |
| int err = 0; |
| switch (ctrl) { |
| case HWC_CTL_FORCE_GPU: |
| case HWC_CTL_WINDOW_UPDATE: |
| case HWC_CTL_FORCE_PANIC: |
| case HWC_CTL_SKIP_STATIC: |
| case HWC_CTL_SKIP_M2M_PROCESSING: |
| case HWC_CTL_SKIP_RESOURCE_ASSIGN: |
| case HWC_CTL_SKIP_VALIDATE: |
| case HWC_CTL_DUMP_MID_BUF: |
| case HWC_CTL_CAPTURE_READBACK: |
| case HWC_CTL_ENABLE_COMPOSITION_CROP: |
| case HWC_CTL_ENABLE_EXYNOSCOMPOSITION_OPT: |
| case HWC_CTL_ENABLE_CLIENTCOMPOSITION_OPT: |
| case HWC_CTL_USE_MAX_G2D_SRC: |
| case HWC_CTL_ENABLE_HANDLE_LOW_FPS: |
| case HWC_CTL_ENABLE_EARLY_START_MPP: |
| case HWC_CTL_DISPLAY_MODE: |
| case HWC_CTL_DDI_RESOLUTION_CHANGE: |
| case HWC_CTL_ENABLE_FENCE_TRACER: |
| case HWC_CTL_SYS_FENCE_LOGGING: |
| case HWC_CTL_DO_FENCE_FILE_DUMP: |
| ALOGI("%s::%d on/off=%d", __func__, ctrl, val); |
| mHWCCtx->device->setHWCControl(display, ctrl, val); |
| break; |
| default: |
| ALOGE("%s: unsupported HWC_CTL, (%d)", __func__, ctrl); |
| err = -1; |
| break; |
| } |
| return err; |
| } |
| |
| int ExynosHWCService::setDDIScaler(uint32_t width, uint32_t height) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s, width=%d, height=%d", __func__, width, height); |
| if (mHWCCtx) { |
| ExynosDisplay *display = (ExynosDisplay*)mHWCCtx->device->getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); |
| |
| if (display == NULL) |
| return -EINVAL; |
| |
| display->setDDIScalerEnable(width, height); |
| return NO_ERROR; |
| } else { |
| ALOGE_IF(HWC_SERVICE_DEBUG, "Service is not exist"); |
| return -EINVAL; |
| } |
| } |
| |
| #if 0 |
| void ExynosHWCService::setPSRExitCallback(void (*callback)(exynos_hwc_composer_device_1_t *)) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s, callback %p", __func__, callback); |
| doPSRExit = callback; |
| } |
| |
| void ExynosHWCService::notifyPSRExit() |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s, doPSRExit %p", __func__, doPSRExit); |
| if (doPSRExit != NULL) { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s, line %d", __func__, __LINE__); |
| doPSRExit(mHWCCtx); |
| } |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s, line %d", __func__, __LINE__); |
| } |
| |
| #endif |
| |
| int ExynosHWCService::createServiceLocked() |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s::", __func__); |
| sp<IServiceManager> sm = defaultServiceManager(); |
| sm->addService(String16("Exynos.HWCService"), mHWCService, false); |
| if (sm->checkService(String16("Exynos.HWCService")) != NULL) { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "adding Exynos.HWCService succeeded"); |
| return 0; |
| } else { |
| ALOGE_IF(HWC_SERVICE_DEBUG, "adding Exynos.HWCService failed"); |
| return -1; |
| } |
| } |
| |
| ExynosHWCService *ExynosHWCService::getExynosHWCService() |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s::", __func__); |
| ExynosHWCService& instance = ExynosHWCService::getInstance(); |
| Mutex::Autolock _l(instance.mLock); |
| if (instance.mHWCService == NULL) { |
| instance.mHWCService = &instance; |
| int status = ExynosHWCService::getInstance().createServiceLocked(); |
| if (status != 0) { |
| ALOGE_IF(HWC_SERVICE_DEBUG, "getExynosHWCService failed"); |
| } |
| } |
| return instance.mHWCService; |
| } |
| |
| void ExynosHWCService::setExynosHWCCtx(ExynosHWCCtx *HWCCtx) |
| { |
| ALOGD_IF(HWC_SERVICE_DEBUG, "%s, HWCCtx=%p", __func__, HWCCtx); |
| if(HWCCtx) { |
| mHWCCtx = HWCCtx; |
| } |
| } |
| |
| int32_t ExynosHWCService::setDisplayDeviceMode(int32_t display_id, int32_t mode) |
| { |
| return mHWCCtx->device->setDisplayDeviceMode(display_id, mode); |
| } |
| |
| int32_t ExynosHWCService::setPanelGammaTableSource(int32_t display_id, int32_t type, |
| int32_t source) { |
| return mHWCCtx->device->setPanelGammaTableSource(display_id, type, source); |
| } |
| |
| int32_t ExynosHWCService::setDisplayBrightness(int32_t display_id, float brightness) { |
| if (brightness < 0 || brightness > 1.0) |
| return -EINVAL; |
| |
| auto display = mHWCCtx->device->getDisplay(display_id); |
| |
| if (display != nullptr) |
| return display->setDisplayBrightness(brightness); |
| |
| return -EINVAL; |
| } |
| |
| int32_t ExynosHWCService::setDisplayLhbm(int32_t display_id, uint32_t on) { |
| if (on > 1) return -EINVAL; |
| |
| auto display = mHWCCtx->device->getDisplay(display_id); |
| |
| if (display != nullptr) { |
| display->setLhbmState(!!on); |
| return NO_ERROR; |
| } |
| |
| return -EINVAL; |
| } |
| |
| int32_t ExynosHWCService::setMinIdleRefreshRate(uint32_t display_id, int32_t fps) { |
| ALOGD("ExynosHWCService::%s() display_id(%u) fps(%d)", __func__, display_id, fps); |
| |
| auto display = mHWCCtx->device->getDisplay(display_id); |
| |
| if (display != nullptr) { |
| return display->setMinIdleRefreshRate(fps); |
| } |
| |
| return -EINVAL; |
| } |
| |
| int32_t ExynosHWCService::setRefreshRateThrottle(uint32_t display_id, int32_t delayMs) { |
| ALOGD("ExynosHWCService::%s() display_id(%u) delayMs(%d)", __func__, display_id, delayMs); |
| |
| auto display = mHWCCtx->device->getDisplay(display_id); |
| |
| if (display != nullptr) { |
| return display |
| ->setRefreshRateThrottleNanos(std::chrono::duration_cast<std::chrono::nanoseconds>( |
| std::chrono::milliseconds(delayMs)) |
| .count(), |
| DispIdleTimerRequester::TEST); |
| } |
| |
| return -EINVAL; |
| } |
| |
| int32_t ExynosHWCService::setDisplayRCDLayerEnabled(uint32_t displayIndex, bool enable) { |
| ALOGD("ExynosHWCService::%s() displayIndex(%u) enable(%u)", __func__, displayIndex, enable); |
| |
| auto primaryDisplay = |
| mHWCCtx->device->getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, displayIndex)); |
| if (primaryDisplay == nullptr) return -EINVAL; |
| |
| auto ret = primaryDisplay->setDebugRCDLayerEnabled(enable); |
| |
| mHWCCtx->device->setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); |
| mHWCCtx->device->onRefresh(); |
| |
| return ret; |
| } |
| |
| int32_t ExynosHWCService::triggerDisplayIdleEnter(uint32_t displayIndex, |
| uint32_t idleTeRefreshRate) { |
| ALOGD("ExynosHWCService::%s() displayIndex(%u) idleTeRefreshRate(%u)", __func__, displayIndex, |
| idleTeRefreshRate); |
| |
| auto primaryDisplay = |
| mHWCCtx->device->getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, displayIndex)); |
| if (primaryDisplay == nullptr) return -EINVAL; |
| |
| mHWCCtx->device->onVsyncIdle(primaryDisplay->getId()); |
| primaryDisplay->handleDisplayIdleEnter(idleTeRefreshRate); |
| |
| return NO_ERROR; |
| } |
| |
| } //namespace android |