blob: 4711eed34478354049d318f9f5600b6e9fd731ab [file] [log] [blame]
/*
* Copyright (c) 2021 The Linux Foundation. All rights reserved.
*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 "DisplayConfigAIDL.h"
using sdm::Locker;
using ::aidl::android::hardware::common::NativeHandle;
namespace aidl {
namespace vendor {
namespace qti {
namespace hardware {
namespace display {
namespace config {
DisplayConfigAIDL::DisplayConfigAIDL(){
hwc_session_ = HWCSession::GetInstance();
}
DisplayConfigAIDL::DisplayConfigAIDL(HWCSession *hwc_session){
if (!hwc_session) {
ALOGE("%s: hwc_session:%p is invalid", __FUNCTION__, hwc_session);
} else {
hwc_session_ = hwc_session;
}
}
int MapDisplayType(DisplayType dpy) {
switch (dpy) {
case DisplayType::PRIMARY:
return qdutils::DISPLAY_PRIMARY;
case DisplayType::EXTERNAL:
return qdutils::DISPLAY_EXTERNAL;
case DisplayType::VIRTUAL:
return qdutils::DISPLAY_VIRTUAL;
case DisplayType::BUILTIN2:
return qdutils::DISPLAY_BUILTIN_2;
default:
break;
}
return -EINVAL;
}
sdm::HWCDisplay::DisplayStatus MapExternalStatus(ExternalStatus status) {
switch (status) {
case ExternalStatus::OFFLINE:
return sdm::HWCDisplay::kDisplayStatusOffline;
case ExternalStatus::ONLINE:
return sdm::HWCDisplay::kDisplayStatusOnline;
case ExternalStatus::PAUSE:
return sdm::HWCDisplay::kDisplayStatusPause;
case ExternalStatus::RESUME:
return sdm::HWCDisplay::kDisplayStatusResume;
default:
break;
}
return sdm::HWCDisplay::kDisplayStatusInvalid;
}
int DisplayConfigAIDL::IsPowerModeOverrideSupported(uint32_t disp_id, bool *supported) {
if (!hwc_session_->async_powermode_ || (disp_id > sdm::HWCCallbacks::kNumRealDisplays)) {
ALOGW("%s: Power mode override is not supported on display:%d", __FUNCTION__, disp_id);
*supported = false;
} else {
*supported = true;
}
return 0;
}
bool WaitForResourceNeeded(HWC2::PowerMode prev_mode, HWC2::PowerMode new_mode) {
return ((prev_mode == HWC2::PowerMode::Off) &&
(new_mode == HWC2::PowerMode::On || new_mode == HWC2::PowerMode::Doze));
}
ScopedAStatus DisplayConfigAIDL::isDisplayConnected(DisplayType dpy, bool* connected) {
int disp_id = MapDisplayType(dpy);
int disp_idx = hwc_session_->GetDisplayIndex(disp_id);
if (disp_idx == -1) {
ALOGE("%s: Invalid display = %d", __FUNCTION__, disp_id);
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
} else {
SEQUENCE_WAIT_SCOPE_LOCK(hwc_session_->locker_[disp_idx]);
*connected = hwc_session_->hwc_display_[disp_idx];
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::setDisplayStatus(DisplayType dpy, ExternalStatus status) {
int disp_id = MapDisplayType(dpy);
sdm::HWCDisplay::DisplayStatus external_status = MapExternalStatus(status);
if (hwc_session_->SetDisplayStatus(disp_id, external_status) != 0) {
ALOGW("%s: Setting status:%d to display:%d failed", __FUNCTION__, status, disp_id);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::configureDynRefreshRate(DynRefreshRateOp op, int refreshRate) {
SEQUENCE_WAIT_SCOPE_LOCK(hwc_session_->locker_[HWC_DISPLAY_PRIMARY]);
sdm::HWCDisplay *hwc_display = hwc_session_->hwc_display_[HWC_DISPLAY_PRIMARY];
if (!hwc_display) {
ALOGW("%s: Display = %d is not connected.", __FUNCTION__, HWC_DISPLAY_PRIMARY);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
switch (op) {
case DynRefreshRateOp::DISABLE_METADATA:
hwc_display->Perform(sdm::HWCDisplayBuiltIn::SET_METADATA_DYN_REFRESH_RATE, false);
break;
case DynRefreshRateOp::ENABLE_METADATA:
hwc_display->Perform(sdm::HWCDisplayBuiltIn::SET_METADATA_DYN_REFRESH_RATE, true);
break;
case DynRefreshRateOp::SET_BINDER:
hwc_display->Perform(sdm::HWCDisplayBuiltIn::SET_BINDER_DYN_REFRESH_RATE, refreshRate);
break;
default:
ALOGW("%s: Invalid operation %d", __FUNCTION__, op);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::getConfigCount(DisplayType dpy, int* count) {
int error = hwc_session_->GetConfigCount(MapDisplayType(dpy), (uint32_t*) count);
if (error == -EINVAL) {
ALOGW("%s: Failed to retrieve config count for display:%d", __FUNCTION__, dpy);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::getActiveConfig(DisplayType dpy, int* config) {
int disp_id = MapDisplayType(dpy);
int error = hwc_session_->GetActiveConfigIndex(disp_id, (uint32_t*) config);
if (error == -EINVAL) {
ALOGW("%s: Failed to retrieve the active config index for display:%d", __FUNCTION__, dpy);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::setActiveConfig(DisplayType dpy, int config) {
int disp_id = MapDisplayType(dpy);
if (hwc_session_->SetActiveConfigIndex(disp_id, (uint32_t) config) == -EINVAL) {
ALOGW("%s: Failed to set active config index to display:%d", __FUNCTION__, dpy);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::getDisplayAttributes(int configIndex, DisplayType dpy,
Attributes* attributes) {
int error = -EINVAL;
int disp_id = MapDisplayType(dpy);
int disp_idx = hwc_session_->GetDisplayIndex(disp_id);
if (disp_idx == -1) {
ALOGW("%s: Invalid display = %d", __FUNCTION__, disp_id);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
} else {
SEQUENCE_WAIT_SCOPE_LOCK(hwc_session_->locker_[disp_idx]);
if (hwc_session_->hwc_display_[disp_idx]) {
sdm::DisplayConfigVariableInfo var_info;
error = hwc_session_->hwc_display_[disp_idx]->GetDisplayAttributesForConfig(INT(configIndex),
&var_info);
if (!error) {
attributes->vsyncPeriod = var_info.vsync_period_ns;
attributes->xRes = var_info.x_pixels;
attributes->yRes = var_info.y_pixels;
attributes->xDpi = var_info.x_dpi;
attributes->yDpi = var_info.y_dpi;
attributes->panelType = DisplayPortType::DEFAULT;
attributes->isYuv = var_info.is_yuv;
}
}
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::setPanelBrightness(int level) {
if (!(0 <= level && level <= 255)) {
ALOGW("%s: Invalid panel brightness level :%d", __FUNCTION__, level);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
if (level == 0) {
hwc_session_->SetDisplayBrightness(HWC_DISPLAY_PRIMARY, -1.0f);
} else {
hwc_session_->SetDisplayBrightness(HWC_DISPLAY_PRIMARY, (level - 1)/254.0f);
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::getPanelBrightness(int* level) {
float brightness = -1.0f;
hwc_session_->getDisplayBrightness(HWC_DISPLAY_PRIMARY, &brightness);
if (brightness == -1.0f) {
*level = 0;
} else {
*level = static_cast<uint32_t>(254.0f*brightness + 1);
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::minHdcpEncryptionLevelChanged(DisplayType dpy, int minEncLevel) {
hwc_session_->MinHdcpEncryptionLevelChanged(MapDisplayType(dpy), minEncLevel);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::refreshScreen() {
SEQUENCE_WAIT_SCOPE_LOCK(hwc_session_->locker_[HWC_DISPLAY_PRIMARY]);
hwc_session_->callbacks_.Refresh(HWC_DISPLAY_PRIMARY);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::controlPartialUpdate(DisplayType dpy, bool enable) {
hwc_session_->ControlPartialUpdate(MapDisplayType(dpy), enable);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::toggleScreenUpdate(bool on) {
hwc_session_->ToggleScreenUpdate(on);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::setIdleTimeout(int value) {
hwc_session_->SetIdleTimeout(value);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::getHDRCapabilities(DisplayType dpy, HDRCapsParams* caps) {
int error = -EINVAL;
do {
int disp_id = MapDisplayType(dpy);
int disp_idx = hwc_session_->GetDisplayIndex(disp_id);
if (disp_idx == -1) {
ALOGE("Invalid display = %d", disp_id);
break;
}
SCOPE_LOCK(hwc_session_->locker_[disp_id]);
sdm::HWCDisplay *hwc_display = hwc_session_->hwc_display_[disp_idx];
if (!hwc_display) {
ALOGW("Display = %d is not connected.", disp_idx);
error = -ENODEV;
break;
}
// query number of hdr types
uint32_t out_num_types = 0;
float out_max_luminance = 0.0f;
float out_max_average_luminance = 0.0f;
float out_min_luminance = 0.0f;
if (hwc_display->GetHdrCapabilities(&out_num_types, nullptr, &out_max_luminance,
&out_max_average_luminance, &out_min_luminance)
!= HWC2::Error::None) {
break;
}
if (!out_num_types) {
error = 0;
break;
}
// query hdr caps
caps->supportedHdrTypes.resize(out_num_types);
if (hwc_display->GetHdrCapabilities(&out_num_types, caps->supportedHdrTypes.data(),
&out_max_luminance, &out_max_average_luminance,
&out_min_luminance) == HWC2::Error::None) {
error = 0;
}
} while (false);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::setCameraLaunchStatus(int on) {
hwc_session_->SetCameraLaunchStatus(on);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::displayBWTransactionPending(bool* status) {
hwc_session_->DisplayBWTransactionPending(status);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::setDisplayAnimating(long displayId, bool animating) {
hwc_session_->CallDisplayFunction(displayId, &sdm::HWCDisplay::SetDisplayAnimating, animating);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::controlIdlePowerCollapse(bool enable, bool synchronous) {
hwc_session_->ControlIdlePowerCollapse(enable, synchronous);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::getWriteBackCapabilities(bool* isWbUbwcSupported) {
hwc_session_->IsWbUbwcSupported(isWbUbwcSupported);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::setDisplayDppsAdROI(int displayId, int hStart, int hEnd,
int vStart, int vEnd, int factorIn, int factorOut) {
hwc_session_->SetDisplayDppsAdROI(displayId, hStart, hEnd, vStart, vEnd, factorIn, factorOut);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::updateVSyncSourceOnPowerModeOff() {
hwc_session_->update_vsync_on_power_off_ = true;
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::updateVSyncSourceOnPowerModeDoze() {
hwc_session_->update_vsync_on_doze_ = true;
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::setPowerMode(int dispId, PowerMode powerMode) {
SCOPE_LOCK(hwc_session_->display_config_locker_);
bool supported = false;
IsPowerModeOverrideSupported(dispId, &supported);
if (!supported) {
ALOGW("%s: Set power mode:%d on display:%d is not supported", __FUNCTION__, powerMode, dispId);
return ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
}
// Active builtin display needs revalidation
hwc2_display_t active_builtin_disp_id = hwc_session_->GetActiveBuiltinDisplay();
HWC2::PowerMode previous_mode = hwc_session_->hwc_display_[dispId]->GetCurrentPowerMode();
ALOGI("%s: disp_id: %d power_mode: %d", __FUNCTION__, dispId, powerMode);
sdm::HWCDisplay::HWCLayerStack stack = {};
hwc2_display_t dummy_disp_id = hwc_session_->map_hwc_display_.at(dispId);
// Power state transition start.
// Acquire the display's power-state transition var read lock.
hwc_session_->power_state_[dispId].Lock();
hwc_session_->power_state_transition_[dispId] = true;
hwc_session_->locker_[dispId].Lock(); // Lock the real display.
hwc_session_->locker_[dummy_disp_id].Lock(); // Lock the corresponding dummy display.
// Place the real display's layer-stack on the dummy display.
hwc_session_->hwc_display_[dispId]->GetLayerStack(&stack);
hwc_session_->hwc_display_[dummy_disp_id]->SetLayerStack(&stack);
hwc_session_->hwc_display_[dummy_disp_id]->UpdatePowerMode(
hwc_session_->hwc_display_[dispId]->GetCurrentPowerMode());
hwc_session_->locker_[dummy_disp_id].Unlock(); // Release the dummy display.
// Release the display's power-state transition var read lock.
hwc_session_->power_state_[dispId].Unlock();
// From now, till power-state transition ends, for operations that need to be non-blocking, do
// those operations on the dummy display.
// Perform the actual [synchronous] power-state change.
hwc_session_->hwc_display_[dispId]->SetPowerMode(static_cast<HWC2::PowerMode>(powerMode),
false /* teardown */);
// Power state transition end.
// Acquire the display's power-state transition var read lock.
hwc_session_->power_state_[dispId].Lock();
hwc_session_->power_state_transition_[dispId] = false;
hwc_session_->locker_[dummy_disp_id].Lock(); // Lock the dummy display.
// Retrieve the real display's layer-stack from the dummy display.
hwc_session_->hwc_display_[dummy_disp_id]->GetLayerStack(&stack);
hwc_session_->hwc_display_[dispId]->SetLayerStack(&stack);
// Read display has got layerstack. Update the fences.
hwc_session_->hwc_display_[dispId]->PostPowerMode();
hwc_session_->locker_[dummy_disp_id].Unlock(); // Release the dummy display.
hwc_session_->locker_[dispId].Unlock(); // Release the real display.
// Release the display's power-state transition var read lock.
hwc_session_->power_state_[dispId].Unlock();
HWC2::PowerMode new_mode = hwc_session_->hwc_display_[dispId]->GetCurrentPowerMode();
if (active_builtin_disp_id < sdm::HWCCallbacks::kNumRealDisplays &&
hwc_session_->hwc_display_[dispId]->IsFirstCommitDone() &&
WaitForResourceNeeded(previous_mode, new_mode)) {
hwc_session_->WaitForResources(true, active_builtin_disp_id, dispId);
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::isPowerModeOverrideSupported(int dispId, bool* supported) {
if (!hwc_session_->async_powermode_ || (dispId > sdm::HWCCallbacks::kNumRealDisplays)) {
*supported = false;
} else {
*supported = true;
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::isHDRSupported(int dispId, bool* supported) {
if (dispId < 0 || dispId >= sdm::HWCCallbacks::kNumDisplays) {
ALOGW("%s: Not valid display", __FUNCTION__);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
SCOPE_LOCK(hwc_session_->hdr_locker_[dispId]);
if (hwc_session_->is_hdr_display_.size() <= dispId) {
ALOGW("%s: is_hdr_display_ is not initialized for display %d!! Reporting it as HDR not " \
"supported", __FUNCTION__, dispId);
*supported = false;
return ScopedAStatus::ok();
}
*supported = static_cast<bool>(hwc_session_->is_hdr_display_[dispId]);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::isWCGSupported(int dispId, bool* supported) {
isHDRSupported(dispId, supported);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::setLayerAsMask(int dispId, long layerId) {
SCOPE_LOCK(hwc_session_->locker_[dispId]);
sdm::HWCDisplay *hwc_display = hwc_session_->hwc_display_[dispId];
if (!hwc_display) {
ALOGW("%s: Display = %d is not connected.", __FUNCTION__, dispId);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
if (hwc_session_->disable_mask_layer_hint_) {
ALOGW("%s: Mask layer hint is disabled!", __FUNCTION__);
return ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
}
auto hwc_layer = hwc_display->GetHWCLayer(layerId);
if (hwc_layer == nullptr) {
ALOGW("%s: Failed to retrieve the hwc layer fpr display:%d", __FUNCTION__, dispId);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
hwc_layer->SetLayerAsMask();
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::getDebugProperty(const std::string& propName,
std::string* value) {
std::string vendor_prop_name = DISP_PROP_PREFIX;
int error = -EINVAL;
char val[64] = {};
vendor_prop_name += propName.c_str();
if (sdm::HWCDebugHandler::Get()->GetProperty(vendor_prop_name.c_str(), val) == sdm::kErrorNone) {
*value = val;
error = 0;
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::getActiveBuiltinDisplayAttributes(Attributes* attr) {
int error = -EINVAL;
hwc2_display_t disp_id = hwc_session_->GetActiveBuiltinDisplay();
if (disp_id >= sdm::HWCCallbacks::kNumDisplays) {
ALOGE("%s: Invalid display = %lu", __FUNCTION__, disp_id);
} else {
if (hwc_session_->hwc_display_[disp_id]) {
uint32_t config_index = 0;
HWC2::Error ret = hwc_session_->hwc_display_[disp_id]->GetActiveConfig(&config_index);
if (ret != HWC2::Error::None) {
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
sdm::DisplayConfigVariableInfo var_info;
error = hwc_session_->hwc_display_[disp_id]->GetDisplayAttributesForConfig(INT(config_index),
&var_info);
if (!error) {
attr->vsyncPeriod = var_info.vsync_period_ns;
attr->xRes = var_info.x_pixels;
attr->yRes = var_info.y_pixels;
attr->xDpi = var_info.x_dpi;
attr->yDpi = var_info.y_dpi;
attr->panelType = DisplayPortType::DEFAULT;
attr->isYuv = var_info.is_yuv;
}
}
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::setPanelLuminanceAttributes(int dispId, float minLum,
float maxLum) {
// currently doing only for virtual display
if (dispId != static_cast<int>(DisplayType::VIRTUAL)) {
ALOGW("%s: Setting panel luminance on non virtual display is not supported", __FUNCTION__);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
// check for out of range luminance values
if (minLum <= 0.0f || minLum >= 1.0f ||
maxLum <= 100.0f || maxLum >= 1000.0f) {
ALOGW("%s: Luminance values are out of range : minimum_luminance:%f maximum_luminance:%f",
__FUNCTION__, minLum, maxLum);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
std::lock_guard<std::mutex> obj(hwc_session_->mutex_lum_);
hwc_session_->set_min_lum_ = minLum;
hwc_session_->set_max_lum_ = maxLum;
ALOGI("%s: set max_lum %f, min_lum %f", __FUNCTION__, maxLum, minLum);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::isBuiltInDisplay(int dispId, bool* isBuiltIn) {
if ((hwc_session_->map_info_primary_.client_id == dispId) &&
(hwc_session_->map_info_primary_.disp_type == sdm::kBuiltIn)) {
*isBuiltIn = true;
return ScopedAStatus::ok();
}
for (auto &info : hwc_session_->map_info_builtin_) {
if (dispId == info.client_id) {
*isBuiltIn = true;
return ScopedAStatus::ok();
}
}
*isBuiltIn = false;
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::isAsyncVDSCreationSupported(bool* supported) {
if (!hwc_session_->async_vds_creation_) {
*supported = false;
return ScopedAStatus::ok();
}
*supported = true;
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::createVirtualDisplay(int width, int height, int format) {
if (!hwc_session_->async_vds_creation_) {
ALOGW("%s: Asynchronous virtual display creation is not supported.", __FUNCTION__);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
if (!width || !height) {
ALOGW("%s: Width and height provided are invalid.", __FUNCTION__);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
hwc2_display_t virtual_id;
hwc2_display_t active_builtin_disp_id = hwc_session_->GetActiveBuiltinDisplay();
auto status = hwc_session_->CreateVirtualDisplayObj(width, height, &format,
&virtual_id);
if (status == HWC2::Error::None) {
ALOGI("%s, Created virtual display id:%" PRIu64 ", res: %dx%d",
__FUNCTION__, virtual_id, width, height);
if (active_builtin_disp_id < sdm::HWCCallbacks::kNumRealDisplays) {
hwc_session_->WaitForResources(true, active_builtin_disp_id, virtual_id);
}
} else {
ALOGE("%s: Failed to create virtual display: %s", __FUNCTION__, to_string(status).c_str());
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::getSupportedDSIBitClks(int dispId, std::vector<long>* bitClks) {
SCOPE_LOCK(hwc_session_->locker_[dispId]);
if (!hwc_session_->hwc_display_[dispId]) {
ALOGW("%s: Display:%d is not connected", __FUNCTION__, dispId);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
hwc_session_->hwc_display_[dispId]->GetSupportedDSIClock((std::vector<uint64_t>*) bitClks);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::getDSIClk(int dispId, long* bitClk) {
SCOPE_LOCK(hwc_session_->locker_[dispId]);
if (!hwc_session_->hwc_display_[dispId]) {
ALOGW("%s: Invalid display:%d", __FUNCTION__, dispId);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
hwc_session_->hwc_display_[dispId]->GetDynamicDSIClock((uint64_t*)bitClk);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::setDSIClk(int dispId, long bitClk) {
SCOPE_LOCK(hwc_session_->locker_[dispId]);
if (!hwc_session_->hwc_display_[dispId]) {
ALOGW("%s: Invalid display:%d", __FUNCTION__, dispId);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
hwc_session_->hwc_display_[dispId]->SetDynamicDSIClock(bitClk);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::setQsyncMode(int dispId, QsyncMode mode) {
SEQUENCE_WAIT_SCOPE_LOCK(hwc_session_->locker_[dispId]);
if (!hwc_session_->hwc_display_[dispId]) {
ALOGW("%s: Invalid display:%d", __FUNCTION__, dispId);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
sdm::QSyncMode qsync_mode = sdm::kQSyncModeNone;
switch (mode) {
case QsyncMode::NONE:
qsync_mode = sdm::kQSyncModeNone;
break;
case QsyncMode::WAIT_FOR_FENCES_ONE_FRAME:
qsync_mode = sdm::kQsyncModeOneShot;
break;
case QsyncMode::WAIT_FOR_FENCES_EACH_FRAME:
qsync_mode = sdm::kQsyncModeOneShotContinuous;
break;
case QsyncMode::WAIT_FOR_COMMIT_EACH_FRAME:
qsync_mode = sdm::kQSyncModeContinuous;
break;
}
hwc_session_->hwc_display_[dispId]->SetQSyncMode(qsync_mode);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::isSmartPanelConfig(int dispId, int configId, bool* isSmart) {
SCOPE_LOCK(hwc_session_->locker_[dispId]);
if (!hwc_session_->hwc_display_[dispId]) {
ALOGE("%s: Display %d is not created yet.", __FUNCTION__, dispId);
*isSmart = false;
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
if (hwc_session_->hwc_display_[dispId]->GetDisplayClass() != sdm::DISPLAY_CLASS_BUILTIN) {
ALOGW("%s: Smart panel config is only supported on built in displays.", __FUNCTION__);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
*isSmart = hwc_session_->hwc_display_[dispId]->IsSmartPanelConfig(configId);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::isRotatorSupportedFormat(int halFormat, bool ubwc,
bool* supported) {
if (!hwc_session_->core_intf_) {
ALOGW("%s: core_intf_ not initialized.", __FUNCTION__);
*supported = false;
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
int flag = ubwc ? qtigralloc::PRIV_FLAGS_UBWC_ALIGNED : 0;
sdm::LayerBufferFormat sdm_format = sdm::HWCLayer::GetSDMFormat(halFormat, flag);
*supported = hwc_session_->core_intf_->IsRotatorSupportedFormat(sdm_format);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::controlQsyncCallback(bool enable) {
if (enable) {
hwc_session_->qsync_callback_ = callback_;
} else {
hwc_session_->qsync_callback_.reset();
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::sendTUIEvent(DisplayType dpy, TUIEventType eventType) {
int disp_id = MapDisplayType(dpy);
switch(eventType) {
case TUIEventType::PREPARE_TUI_TRANSITION:
hwc_session_->TUITransitionPrepare(disp_id);
break;
case TUIEventType::START_TUI_TRANSITION:
hwc_session_->TUITransitionStart(disp_id);
break;
case TUIEventType::END_TUI_TRANSITION:
hwc_session_->TUITransitionEnd(disp_id);
break;
default:
ALOGE("%s: Invalid event %d", __FUNCTION__, eventType);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::getDisplayHwId(int dispId, int* displayHwId) {
int disp_idx = hwc_session_->GetDisplayIndex(dispId);
if (disp_idx == -1) {
ALOGE("%s: Invalid display = %d", __FUNCTION__, dispId);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
SCOPE_LOCK(hwc_session_->locker_[dispId]);
if (!hwc_session_->hwc_display_[disp_idx]) {
ALOGW("%s: Display %d is not connected.", __FUNCTION__, dispId);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
// Supported for Built-In displays only.
if ((hwc_session_->map_info_primary_.client_id == dispId) &&
(hwc_session_->map_info_primary_.disp_type == sdm::kBuiltIn)) {
if (hwc_session_->map_info_primary_.sdm_id >= 0) {
*displayHwId = static_cast<uint32_t>(hwc_session_->map_info_primary_.sdm_id);
return ScopedAStatus::ok();
}
}
for (auto &info : hwc_session_->map_info_builtin_) {
if (dispId == info.client_id) {
if (info.sdm_id >= 0) {
*displayHwId = static_cast<uint32_t>(info.sdm_id);
return ScopedAStatus::ok();
}
}
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::getSupportedDisplayRefreshRates(DisplayType dpy,
std::vector<int>* supportedRefreshRates) {
hwc_session_->GetSupportedDisplayRefreshRates(MapDisplayType(dpy),
(std::vector<uint32_t> *) supportedRefreshRates);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::isRCSupported(int dispId, bool* supported) {
// Mask layers can potentially be shown on any display so report RC supported on all displays if
// the property enables the feature for use.
int val = false; // Default value.
sdm::Debug::GetProperty(ENABLE_ROUNDED_CORNER, &val);
*supported = val ? true: false;
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::controlIdleStatusCallback(bool enable) {
if (enable) {
hwc_session_->idle_callback_ = callback_;
} else {
hwc_session_->idle_callback_.reset();
}
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::isSupportedConfigSwitch(int dispId, int config, bool* supported) {
if (!hwc_session_) {
ALOGW("%s: Invalid hwc session:%p found.", __FUNCTION__, hwc_session_);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
int disp_idx = hwc_session_->GetDisplayIndex(dispId);
if (disp_idx == -1) {
ALOGW("%s: Invalid display = %d", __FUNCTION__, dispId);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
SCOPE_LOCK(hwc_session_->locker_[disp_idx]);
if (!hwc_session_->hwc_display_[disp_idx]) {
ALOGW("%s: Display %d is not connected.", __FUNCTION__, dispId);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
*supported = hwc_session_->hwc_display_[disp_idx]->IsModeSwitchAllowed(config);
return ScopedAStatus::ok();
}
DisplayType GetDisplayConfigDisplayType(int qdutils_disp_type) {
switch (qdutils_disp_type) {
case qdutils::DISPLAY_PRIMARY:
return DisplayType::PRIMARY;
case qdutils::DISPLAY_EXTERNAL:
return DisplayType::EXTERNAL;
case qdutils::DISPLAY_VIRTUAL:
return DisplayType::VIRTUAL;
case qdutils::DISPLAY_BUILTIN_2:
return DisplayType::BUILTIN2;
default:
return DisplayType::INVALID;
}
}
int DisplayConfigAIDL::GetDispTypeFromPhysicalId(uint64_t physical_disp_id,
DisplayType *disp_type) {
// TODO(user): Least significant 8 bit is port id based on the SF current implementaion. Need to
// revisit this if there is a change in logic to create physical display id in SF.
int port_id = (physical_disp_id & 0xFF);
int out_port = 0;
for (int dpy = qdutils::DISPLAY_PRIMARY; dpy <= qdutils::DISPLAY_EXTERNAL_2; dpy++) {
int ret = hwc_session_->GetDisplayPortId(dpy, &out_port);
if (ret != 0){
return ret;
}
if (port_id == out_port) {
*disp_type = GetDisplayConfigDisplayType(dpy);
return 0;
}
}
return -ENODEV;
}
ScopedAStatus DisplayConfigAIDL::getDisplayType(long physicalDispId, DisplayType* displayType) {
if (!displayType) {
ALOGW("%s: Display type provided is invalid.", __FUNCTION__);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
GetDispTypeFromPhysicalId(physicalDispId, displayType);
return ScopedAStatus::ok();
}
ScopedAStatus
DisplayConfigAIDL::setCWBOutputBuffer(const std::shared_ptr<IDisplayConfigCallback>& callback,
int32_t dispId, const Rect& rect, bool postProcessed,
const NativeHandle& buffer) {
if (!callback_.lock()) {
ALOGE("%s: Callback_ has not yet been initialized.", __FUNCTION__);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
// Output buffer dump is not supported, if Virtual display is present.
int dpy_index = hwc_session_->GetDisplayIndex(qdutils::DISPLAY_VIRTUAL);
if ((dpy_index != -1) && hwc_session_->hwc_display_[dpy_index]) {
ALOGW("Output buffer dump is not supported with Virtual display!");
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
hwc2_display_t disp_type = HWC_DISPLAY_PRIMARY;
if (dispId == UINT32(DisplayType::PRIMARY)) {
dpy_index = hwc_session_->GetDisplayIndex(qdutils::DISPLAY_PRIMARY);
} else if (dispId == UINT32(DisplayType::EXTERNAL)) {
dpy_index = hwc_session_->GetDisplayIndex(qdutils::DISPLAY_EXTERNAL);
disp_type = HWC_DISPLAY_EXTERNAL;
} else if (dispId == UINT32(DisplayType::BUILTIN2)) {
dpy_index = hwc_session_->GetDisplayIndex(qdutils::DISPLAY_BUILTIN_2);
disp_type = HWC_DISPLAY_BUILTIN_2;
} else {
ALOGE("%s: CWB is supported on primary or external display only at present.", __FUNCTION__);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
if (dpy_index == -1) {
ALOGW("Unable to retrieve display index for display:%d", dispId);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
// Mutex scope
{
SCOPE_LOCK(hwc_session_->locker_[disp_type]);
if (!hwc_session_->hwc_display_[dpy_index]) {
ALOGE("%s: Display is not created yet.", __FUNCTION__);
return ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
}
sdm::CwbConfig cwb_config = {};
cwb_config.tap_point = static_cast<sdm::CwbTapPoint>(postProcessed);
sdm::LayerRect &roi = cwb_config.cwb_roi;
roi.left = FLOAT(rect.left);
roi.top = FLOAT(rect.top);
roi.right = FLOAT(rect.right);
roi.bottom = FLOAT(rect.bottom);
ALOGI("CWB config passed by cwb_client : tappoint %d CWB_ROI : (%f %f %f %f)",
cwb_config.tap_point, roi.left, roi.top, roi.right, roi.bottom);
// TODO(user): Convert NativeHandle to native_handle_t, call PostBuffer
hwc_session_->cwb_.PostBuffer(callback_, cwb_config, ::android::dupFromAidl(buffer), disp_type);
return ScopedAStatus::ok();
}
ScopedAStatus DisplayConfigAIDL::setCameraSmoothInfo(CameraSmoothOp op, int32_t fps) {
int ret = -1;
if (fps < 0) {
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
ret = hwc_session_->SetCameraSmoothInfo(op, fps);
return ret == 0 ? ScopedAStatus::ok() : ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
}
ScopedAStatus DisplayConfigAIDL::registerCallback(
const std::shared_ptr<IDisplayConfigCallback>& callback,
int64_t* client_handle) {
int ret = -1;
if (callback == nullptr) {
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
ret = hwc_session_->RegisterCallbackClient(callback, client_handle);
return ret == 0 ? ScopedAStatus::ok() : ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
}
ScopedAStatus DisplayConfigAIDL::unRegisterCallback(int64_t client_handle) {
int ret = -1;
if (client_handle < 0) {
return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
ret = hwc_session_->UnregisterCallbackClient(client_handle);
return ret == 0 ? ScopedAStatus::ok() : ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
}
} // namespace config
} // namespace display
} // namespace hardware
} // namespace qti
} // namespace vendor
} // namespace aidl