blob: d1b0123685c7d4fd56daab75d007229a927ddc49 [file] [log] [blame]
/*
* Copyright (C) 2021 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 "pixel-display.h"
#include <aidlcommonsupport/NativeHandle.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <cstdint>
#include "BrightnessController.h"
#include "ExynosDisplay.h"
#include "ExynosPrimaryDisplay.h"
#include "HistogramController.h"
extern int32_t load_png_image(const char *filepath, buffer_handle_t buffer);
using ::aidl::com::google::hardware::pixel::display::Display;
void PixelDisplayInit(ExynosDisplay *exynos_display, const std::string_view instance_str) {
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<Display> display = ndk::SharedRefBase::make<Display>(exynos_display);
const std::string instance = std::string() + Display::descriptor + "/" + std::string(instance_str).c_str();
binder_status_t status =
AServiceManager_addService(display->asBinder().get(), instance.c_str());
LOG(INFO) << instance.c_str() << " service start...";
CHECK(status == STATUS_OK);
ABinderProcess_startThreadPool();
}
int32_t readCompensationImage(const aidl::android::hardware::common::NativeHandle &handle,
const std::string &imageName) {
ALOGI("setCompensationImageHandle, imageName = %s", imageName.c_str());
std::string shadowCompensationImage("/mnt/vendor/persist/display/");
shadowCompensationImage.append(imageName);
native_handle_t *clone = makeFromAidl(handle);
return load_png_image(shadowCompensationImage.c_str(), static_cast<buffer_handle_t>(clone));
}
namespace aidl {
namespace com {
namespace google {
namespace hardware {
namespace pixel {
namespace display {
// ----------------------------------------------------------------------------
ndk::ScopedAStatus Display::isHbmSupported(bool *_aidl_return) {
*_aidl_return = false;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Display::setHbmState(HbmState state) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::getHbmState(HbmState *_aidl_return) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::isLbeSupported(bool *_aidl_return) {
if (mDisplay) {
*_aidl_return = mDisplay->isLbeSupported();
return ndk::ScopedAStatus::ok();
}
*_aidl_return = false;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Display::setLbeState(LbeState state) {
if (mDisplay) {
mDisplay->setLbeState(state);
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::setLbeAmbientLight(int ambientLux) {
if (mDisplay) {
mDisplay->setLbeAmbientLight(ambientLux);
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::getLbeState(LbeState *_aidl_return) {
if (mDisplay) {
*_aidl_return = mDisplay->getLbeState();
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::isLhbmSupported(bool *_aidl_return) {
if (mDisplay) {
*_aidl_return = mDisplay->isLhbmSupported();
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::setLhbmState(bool enabled) {
if (mDisplay && mDisplay->isLhbmSupported()) {
int32_t ret = mDisplay->setLhbmState(enabled);
if (!ret)
return ndk::ScopedAStatus::ok();
else if (ret == TIMED_OUT)
return ndk::ScopedAStatus::fromExceptionCode(STATUS_TIMED_OUT);
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::getLhbmState(bool *_aidl_return) {
if (mDisplay && mDisplay->isLhbmSupported()) {
*_aidl_return = mDisplay->getLhbmState();
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::setPeakRefreshRate(int rate) {
if (mDisplay && mDisplay->mOperationRateManager) {
mDisplay->mOperationRateManager->onPeakRefreshRate(rate);
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::setLowPowerMode(bool enabled) {
if (mDisplay && mDisplay->mOperationRateManager) {
mDisplay->mOperationRateManager->onLowPowerMode(enabled);
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::isOperationRateSupported(bool *_aidl_return) {
if (mDisplay) {
*_aidl_return = mDisplay->isOperationRateSupported();
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::setCompensationImageHandle(const NativeHandle &native_handle,
const std::string &imageName,
int *_aidl_return) {
if (mDisplay && mDisplay->getPanelCalibrationStatus() == PanelCalibrationStatus::ORIGINAL) {
*_aidl_return = readCompensationImage(native_handle, imageName);
} else {
*_aidl_return = -1;
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Display::setMinIdleRefreshRate(int fps, int *_aidl_return) {
if (mDisplay) {
*_aidl_return = mDisplay->setMinIdleRefreshRate(fps, RrThrottleRequester::PIXEL_DISP);
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::setRefreshRateThrottle(int delayMs, int *_aidl_return) {
if (mDisplay) {
if (delayMs < 0) {
*_aidl_return = BAD_VALUE;
ALOGW("%s fail: delayMs(%d) is less than 0", __func__, delayMs);
return ndk::ScopedAStatus::ok();
}
*_aidl_return =
mDisplay->setRefreshRateThrottleNanos(std::chrono::duration_cast<
std::chrono::nanoseconds>(
std::chrono::milliseconds(delayMs))
.count(),
RrThrottleRequester::PIXEL_DISP);
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
bool Display::runMediator(const RoiRect &roi, const Weight &weight, const HistogramPos &pos,
std::vector<char16_t> *histogrambuffer) {
bool isConfigChanged;
histogram::HistogramMediator::HistogramConfig pendingConfig(roi, weight, pos);
{
std::scoped_lock lock(mMediator.mConfigMutex);
isConfigChanged = mMediator.mConfig != pendingConfig;
if (isConfigChanged) {
if (mMediator.setRoiWeightThreshold(roi, weight, pos) != HistogramErrorCode::NONE) {
ALOGE("histogram error, SET_ROI_WEIGHT_THRESHOLD ERROR\n");
return false;
}
mMediator.mConfig = pendingConfig;
}
}
if (!mMediator.histRequested() &&
mMediator.requestHist() == HistogramErrorCode::ENABLE_HIST_ERROR) {
ALOGE("histogram error, ENABLE_HIST ERROR\n");
}
/*
* DPU driver maintains always-on histogram engine state with up to date histogram data.
* Therefore we don't have explicitly to trigger onRefresh in case histogram configuration
* does not change.
*/
if (isConfigChanged) {
mDisplay->mDevice->onRefresh(mDisplay->mDisplayId);
}
if (mMediator.collectRoiLuma(histogrambuffer) != HistogramErrorCode::NONE) {
ALOGE("histogram error, COLLECT_ROI_LUMA ERROR\n");
return false;
}
return true;
}
ndk::ScopedAStatus Display::histogramSample(const RoiRect &roi, const Weight &weight,
HistogramPos pos, Priority pri,
std::vector<char16_t> *histogrambuffer,
HistogramErrorCode *_aidl_return) {
if (!mDisplay) {
ALOGI("mDisplay is NULL \n");
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
if (histogrambuffer == nullptr) {
ALOGE("histogrambuffer is null");
*_aidl_return = HistogramErrorCode::BAD_HIST_DATA;
return ndk::ScopedAStatus::ok();
}
if (mDisplay->isPowerModeOff() == true) {
*_aidl_return = HistogramErrorCode::DISPLAY_POWEROFF; // panel is off
return ndk::ScopedAStatus::ok();
}
if (mDisplay->isSecureContentPresenting() == true) {
*_aidl_return = HistogramErrorCode::DRM_PLAYING; // panel is playing DRM content
return ndk::ScopedAStatus::ok();
}
if ((roi.left < 0) || (roi.top < 0) || ((roi.right - roi.left) <= 0) ||
((roi.bottom - roi.top) <= 0)) {
*_aidl_return = HistogramErrorCode::BAD_ROI;
ALOGE("histogram error, BAD_ROI (%d, %d, %d, %d) \n", roi.left, roi.top, roi.right,
roi.bottom);
return ndk::ScopedAStatus::ok();
}
if ((weight.weightR + weight.weightG + weight.weightB) != (histogram::WEIGHT_SUM)) {
*_aidl_return = HistogramErrorCode::BAD_WEIGHT;
ALOGE("histogram error, BAD_WEIGHT(%d, %d, %d)\n", weight.weightR, weight.weightG,
weight.weightB);
return ndk::ScopedAStatus::ok();
}
if (pos != HistogramPos::POST && pos != HistogramPos::PRE) {
*_aidl_return = HistogramErrorCode::BAD_POSITION;
ALOGE("histogram error, BAD_POSITION(%d)\n", (int)pos);
return ndk::ScopedAStatus::ok();
}
if (pri != Priority::NORMAL && pri != Priority::PRIORITY) {
*_aidl_return = HistogramErrorCode::BAD_PRIORITY;
ALOGE("histogram error, BAD_PRIORITY(%d)\n", (int)pri);
return ndk::ScopedAStatus::ok();
}
RoiRect roiCaled = mMediator.calRoi(roi); // fit roi coordinates to RRS
runMediator(roiCaled, weight, pos, histogrambuffer);
if (mDisplay->isSecureContentPresenting() == true) {
/* clear data to avoid leakage */
std::fill(histogrambuffer->begin(), histogrambuffer->end(), 0);
histogrambuffer->clear();
*_aidl_return = HistogramErrorCode::DRM_PLAYING; // panel is playing DRM content
return ndk::ScopedAStatus::ok();
}
*_aidl_return = HistogramErrorCode::NONE;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Display::getPanelCalibrationStatus(PanelCalibrationStatus *_aidl_return){
if (mDisplay) {
*_aidl_return = mDisplay->getPanelCalibrationStatus();
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::isDbmSupported(bool *_aidl_return) {
if (!mDisplay) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
*_aidl_return = mDisplay->isDbmSupported();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Display::setDbmState(bool enabled) {
if (!mDisplay) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
mDisplay->setDbmState(enabled);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Display::getHistogramCapability(HistogramCapability *_aidl_return) {
if (mDisplay && mDisplay->mHistogramController) {
return mDisplay->mHistogramController->getHistogramCapability(_aidl_return);
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::registerHistogram(const ndk::SpAIBinder &token,
const HistogramConfig &histogramConfig,
HistogramErrorCode *_aidl_return) {
if (mDisplay && mDisplay->mHistogramController) {
return mDisplay->mHistogramController->registerHistogram(token, histogramConfig,
_aidl_return);
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::queryHistogram(const ndk::SpAIBinder &token,
std::vector<char16_t> *histogramBuffer,
HistogramErrorCode *_aidl_return) {
if (mDisplay && mDisplay->mHistogramController) {
return mDisplay->mHistogramController->queryHistogram(token, histogramBuffer, _aidl_return);
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::reconfigHistogram(const ndk::SpAIBinder &token,
const HistogramConfig &histogramConfig,
HistogramErrorCode *_aidl_return) {
if (mDisplay && mDisplay->mHistogramController) {
return mDisplay->mHistogramController->reconfigHistogram(token, histogramConfig,
_aidl_return);
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::unregisterHistogram(const ndk::SpAIBinder &token,
HistogramErrorCode *_aidl_return) {
if (mDisplay && mDisplay->mHistogramController) {
return mDisplay->mHistogramController->unregisterHistogram(token, _aidl_return);
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::setFixedTe2Rate(int rateHz, int* _aidl_return) {
if (mDisplay) {
*_aidl_return = mDisplay->setFixedTe2Rate(rateHz);
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::queryStats(DisplayStats::Tag tag,
std::optional<DisplayStats>* _aidl_return) {
ATRACE_NAME(
String8::format("%s(%s)", __func__,
aidl::com::google::hardware::pixel::display::toString(tag).c_str()));
if (!mDisplay) {
ALOGW("%s: mDisplay is NULL", __func__);
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
switch (tag) {
case DisplayStats::brightnessNits:
if (mDisplay->mBrightnessController != nullptr) {
auto res = mDisplay->mBrightnessController->getBrightnessNitsAndMode();
if (res != std::nullopt) {
double nits = std::get<float>(res.value());
(*_aidl_return) = DisplayStats::make<DisplayStats::brightnessNits>(nits);
} else {
ALOGW("%s: getBrightnessNitsAndMode returned nullopt!", __func__);
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
} else {
ALOGW("%s: mBrightnessController is null!", __func__);
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
break;
case DisplayStats::brightnessDbv:
if (mDisplay->mBrightnessController != nullptr) {
int dbv = mDisplay->mBrightnessController->getBrightnessLevel();
(*_aidl_return) = DisplayStats::make<DisplayStats::brightnessDbv>(dbv);
} else {
ALOGW("%s: mBrightnessController is null!", __func__);
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
break;
case DisplayStats::operationRate:
if (mDisplay->isOperationRateSupported()) {
int op_hz = mDisplay->mOperationRateManager->getTargetOperationRate();
(*_aidl_return) = DisplayStats::make<DisplayStats::operationRate>(op_hz);
} else {
ALOGW("%s: operation rate not supported!", __func__);
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
break;
case DisplayStats::opr:
if (mDisplay->mHistogramController) {
std::array<double, HistogramController::kOPRConfigsCount> oprVals;
ndk::ScopedAStatus status = mDisplay->mHistogramController->queryOPR(oprVals);
if (!status.isOk()) return status;
(*_aidl_return) = DisplayStats::make<DisplayStats::opr>(oprVals);
} else {
ALOGW("%s: mHistogramController is null!", __func__);
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
break;
default:
ALOGW("%s: invalid stats tag: %u", __func__, (uint32_t)tag);
*_aidl_return = std::nullopt;
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
};
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Display::isProximitySensorStateCallbackSupported(bool* _aidl_return) {
if (mDisplay) {
*_aidl_return = mDisplay->isProximitySensorStateCallbackSupported();
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Display::registerProximitySensorStateChangeCallback(
const std::shared_ptr<IDisplayProximitySensorCallback>& callback) {
if (mDisplay && callback) {
mDisplay->mProximitySensorStateChangeCallback = callback;
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
} // namespace display
} // namespace pixel
} // namespace hardware
} // namespace google
} // namespace com
} // namespace aidl