1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "pixel-display.h"
18
19 #include <aidlcommonsupport/NativeHandle.h>
20 #include <android-base/logging.h>
21 #include <android/binder_manager.h>
22 #include <android/binder_process.h>
23 #include <sys/types.h>
24 #include <utils/Errors.h>
25 #include <cstdint>
26
27 #include "BrightnessController.h"
28 #include "ExynosDisplay.h"
29 #include "ExynosPrimaryDisplay.h"
30 #include "HistogramController.h"
31
32 extern int32_t load_png_image(const char *filepath, buffer_handle_t buffer);
33
34 using ::aidl::com::google::hardware::pixel::display::Display;
35
PixelDisplayInit(ExynosDisplay * exynos_display,const std::string_view instance_str)36 void PixelDisplayInit(ExynosDisplay *exynos_display, const std::string_view instance_str) {
37 ABinderProcess_setThreadPoolMaxThreadCount(0);
38
39 std::shared_ptr<Display> display = ndk::SharedRefBase::make<Display>(exynos_display);
40 const std::string instance = std::string() + Display::descriptor + "/" + std::string(instance_str).c_str();
41 binder_status_t status =
42 AServiceManager_addService(display->asBinder().get(), instance.c_str());
43 LOG(INFO) << instance.c_str() << " service start...";
44 CHECK(status == STATUS_OK);
45
46 ABinderProcess_startThreadPool();
47 }
48
readCompensationImage(const aidl::android::hardware::common::NativeHandle & handle,const std::string & imageName)49 int32_t readCompensationImage(const aidl::android::hardware::common::NativeHandle &handle,
50 const std::string &imageName) {
51 ALOGI("setCompensationImageHandle, imageName = %s", imageName.c_str());
52
53 std::string shadowCompensationImage("/mnt/vendor/persist/display/");
54 shadowCompensationImage.append(imageName);
55
56 native_handle_t *clone = makeFromAidl(handle);
57
58 return load_png_image(shadowCompensationImage.c_str(), static_cast<buffer_handle_t>(clone));
59 }
60
61 namespace aidl {
62 namespace com {
63 namespace google {
64 namespace hardware {
65 namespace pixel {
66 namespace display {
67
68 // ----------------------------------------------------------------------------
69
isHbmSupported(bool * _aidl_return)70 ndk::ScopedAStatus Display::isHbmSupported(bool *_aidl_return) {
71 *_aidl_return = false;
72 return ndk::ScopedAStatus::ok();
73 }
74
setHbmState(HbmState state)75 ndk::ScopedAStatus Display::setHbmState(HbmState state) {
76 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
77 }
78
getHbmState(HbmState * _aidl_return)79 ndk::ScopedAStatus Display::getHbmState(HbmState *_aidl_return) {
80 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
81 }
82
isLbeSupported(bool * _aidl_return)83 ndk::ScopedAStatus Display::isLbeSupported(bool *_aidl_return) {
84 if (mDisplay) {
85 *_aidl_return = mDisplay->isLbeSupported();
86 return ndk::ScopedAStatus::ok();
87 }
88 *_aidl_return = false;
89 return ndk::ScopedAStatus::ok();
90 }
91
setLbeState(LbeState state)92 ndk::ScopedAStatus Display::setLbeState(LbeState state) {
93 if (mDisplay) {
94 mDisplay->setLbeState(state);
95 return ndk::ScopedAStatus::ok();
96 }
97 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
98 }
99
setLbeAmbientLight(int ambientLux)100 ndk::ScopedAStatus Display::setLbeAmbientLight(int ambientLux) {
101 if (mDisplay) {
102 mDisplay->setLbeAmbientLight(ambientLux);
103 return ndk::ScopedAStatus::ok();
104 }
105 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
106 }
107
getLbeState(LbeState * _aidl_return)108 ndk::ScopedAStatus Display::getLbeState(LbeState *_aidl_return) {
109 if (mDisplay) {
110 *_aidl_return = mDisplay->getLbeState();
111 return ndk::ScopedAStatus::ok();
112 }
113 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
114 }
115
isLhbmSupported(bool * _aidl_return)116 ndk::ScopedAStatus Display::isLhbmSupported(bool *_aidl_return) {
117 if (mDisplay) {
118 *_aidl_return = mDisplay->isLhbmSupported();
119 return ndk::ScopedAStatus::ok();
120 }
121 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
122 }
123
setLhbmState(bool enabled)124 ndk::ScopedAStatus Display::setLhbmState(bool enabled) {
125 if (mDisplay && mDisplay->isLhbmSupported()) {
126 int32_t ret = mDisplay->setLhbmState(enabled);
127 if (!ret)
128 return ndk::ScopedAStatus::ok();
129 else if (ret == TIMED_OUT)
130 return ndk::ScopedAStatus::fromExceptionCode(STATUS_TIMED_OUT);
131 }
132 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
133 }
134
getLhbmState(bool * _aidl_return)135 ndk::ScopedAStatus Display::getLhbmState(bool *_aidl_return) {
136 if (mDisplay && mDisplay->isLhbmSupported()) {
137 *_aidl_return = mDisplay->getLhbmState();
138 return ndk::ScopedAStatus::ok();
139 }
140 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
141 }
142
setPeakRefreshRate(int rate)143 ndk::ScopedAStatus Display::setPeakRefreshRate(int rate) {
144 if (mDisplay && mDisplay->mOperationRateManager) {
145 mDisplay->mOperationRateManager->onPeakRefreshRate(rate);
146 return ndk::ScopedAStatus::ok();
147 }
148 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
149 }
150
setLowPowerMode(bool enabled)151 ndk::ScopedAStatus Display::setLowPowerMode(bool enabled) {
152 if (mDisplay && mDisplay->mOperationRateManager) {
153 mDisplay->mOperationRateManager->onLowPowerMode(enabled);
154 return ndk::ScopedAStatus::ok();
155 }
156 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
157 }
158
isOperationRateSupported(bool * _aidl_return)159 ndk::ScopedAStatus Display::isOperationRateSupported(bool *_aidl_return) {
160 if (mDisplay) {
161 *_aidl_return = mDisplay->isOperationRateSupported();
162 return ndk::ScopedAStatus::ok();
163 }
164 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
165 }
166
setCompensationImageHandle(const NativeHandle & native_handle,const std::string & imageName,int * _aidl_return)167 ndk::ScopedAStatus Display::setCompensationImageHandle(const NativeHandle &native_handle,
168 const std::string &imageName,
169 int *_aidl_return) {
170 if (mDisplay && mDisplay->getPanelCalibrationStatus() == PanelCalibrationStatus::ORIGINAL) {
171 *_aidl_return = readCompensationImage(native_handle, imageName);
172 } else {
173 *_aidl_return = -1;
174 }
175 return ndk::ScopedAStatus::ok();
176 }
177
setMinIdleRefreshRate(int fps,int * _aidl_return)178 ndk::ScopedAStatus Display::setMinIdleRefreshRate(int fps, int *_aidl_return) {
179 if (mDisplay) {
180 *_aidl_return = mDisplay->setMinIdleRefreshRate(fps, RrThrottleRequester::PIXEL_DISP);
181 return ndk::ScopedAStatus::ok();
182 }
183 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
184 }
185
setRefreshRateThrottle(int delayMs,int * _aidl_return)186 ndk::ScopedAStatus Display::setRefreshRateThrottle(int delayMs, int *_aidl_return) {
187 if (mDisplay) {
188 if (delayMs < 0) {
189 *_aidl_return = BAD_VALUE;
190 ALOGW("%s fail: delayMs(%d) is less than 0", __func__, delayMs);
191 return ndk::ScopedAStatus::ok();
192 }
193
194 *_aidl_return =
195 mDisplay->setRefreshRateThrottleNanos(std::chrono::duration_cast<
196 std::chrono::nanoseconds>(
197 std::chrono::milliseconds(delayMs))
198 .count(),
199 RrThrottleRequester::PIXEL_DISP);
200 return ndk::ScopedAStatus::ok();
201 }
202 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
203 }
204
runMediator(const RoiRect & roi,const Weight & weight,const HistogramPos & pos,std::vector<char16_t> * histogrambuffer)205 bool Display::runMediator(const RoiRect &roi, const Weight &weight, const HistogramPos &pos,
206 std::vector<char16_t> *histogrambuffer) {
207 bool isConfigChanged;
208 histogram::HistogramMediator::HistogramConfig pendingConfig(roi, weight, pos);
209
210 {
211 std::scoped_lock lock(mMediator.mConfigMutex);
212 isConfigChanged = mMediator.mConfig != pendingConfig;
213
214 if (isConfigChanged) {
215 if (mMediator.setRoiWeightThreshold(roi, weight, pos) != HistogramErrorCode::NONE) {
216 ALOGE("histogram error, SET_ROI_WEIGHT_THRESHOLD ERROR\n");
217 return false;
218 }
219 mMediator.mConfig = pendingConfig;
220 }
221 }
222
223 if (!mMediator.histRequested() &&
224 mMediator.requestHist() == HistogramErrorCode::ENABLE_HIST_ERROR) {
225 ALOGE("histogram error, ENABLE_HIST ERROR\n");
226 }
227
228 /*
229 * DPU driver maintains always-on histogram engine state with up to date histogram data.
230 * Therefore we don't have explicitly to trigger onRefresh in case histogram configuration
231 * does not change.
232 */
233 if (isConfigChanged) {
234 mDisplay->mDevice->onRefresh(mDisplay->mDisplayId);
235 }
236
237 if (mMediator.collectRoiLuma(histogrambuffer) != HistogramErrorCode::NONE) {
238 ALOGE("histogram error, COLLECT_ROI_LUMA ERROR\n");
239 return false;
240 }
241 return true;
242 }
243
histogramSample(const RoiRect & roi,const Weight & weight,HistogramPos pos,Priority pri,std::vector<char16_t> * histogrambuffer,HistogramErrorCode * _aidl_return)244 ndk::ScopedAStatus Display::histogramSample(const RoiRect &roi, const Weight &weight,
245 HistogramPos pos, Priority pri,
246 std::vector<char16_t> *histogrambuffer,
247 HistogramErrorCode *_aidl_return) {
248 if (!mDisplay) {
249 ALOGI("mDisplay is NULL \n");
250 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
251 }
252 if (histogrambuffer == nullptr) {
253 ALOGE("histogrambuffer is null");
254 *_aidl_return = HistogramErrorCode::BAD_HIST_DATA;
255 return ndk::ScopedAStatus::ok();
256 }
257 if (mDisplay->isPowerModeOff() == true) {
258 *_aidl_return = HistogramErrorCode::DISPLAY_POWEROFF; // panel is off
259 return ndk::ScopedAStatus::ok();
260 }
261 if (mDisplay->isSecureContentPresenting() == true) {
262 *_aidl_return = HistogramErrorCode::DRM_PLAYING; // panel is playing DRM content
263 return ndk::ScopedAStatus::ok();
264 }
265 if ((roi.left < 0) || (roi.top < 0) || ((roi.right - roi.left) <= 0) ||
266 ((roi.bottom - roi.top) <= 0)) {
267 *_aidl_return = HistogramErrorCode::BAD_ROI;
268 ALOGE("histogram error, BAD_ROI (%d, %d, %d, %d) \n", roi.left, roi.top, roi.right,
269 roi.bottom);
270 return ndk::ScopedAStatus::ok();
271 }
272 if ((weight.weightR + weight.weightG + weight.weightB) != (histogram::WEIGHT_SUM)) {
273 *_aidl_return = HistogramErrorCode::BAD_WEIGHT;
274 ALOGE("histogram error, BAD_WEIGHT(%d, %d, %d)\n", weight.weightR, weight.weightG,
275 weight.weightB);
276 return ndk::ScopedAStatus::ok();
277 }
278 if (pos != HistogramPos::POST && pos != HistogramPos::PRE) {
279 *_aidl_return = HistogramErrorCode::BAD_POSITION;
280 ALOGE("histogram error, BAD_POSITION(%d)\n", (int)pos);
281 return ndk::ScopedAStatus::ok();
282 }
283 if (pri != Priority::NORMAL && pri != Priority::PRIORITY) {
284 *_aidl_return = HistogramErrorCode::BAD_PRIORITY;
285 ALOGE("histogram error, BAD_PRIORITY(%d)\n", (int)pri);
286 return ndk::ScopedAStatus::ok();
287 }
288 RoiRect roiCaled = mMediator.calRoi(roi); // fit roi coordinates to RRS
289 runMediator(roiCaled, weight, pos, histogrambuffer);
290 if (mDisplay->isSecureContentPresenting() == true) {
291 /* clear data to avoid leakage */
292 std::fill(histogrambuffer->begin(), histogrambuffer->end(), 0);
293 histogrambuffer->clear();
294 *_aidl_return = HistogramErrorCode::DRM_PLAYING; // panel is playing DRM content
295 return ndk::ScopedAStatus::ok();
296 }
297
298 *_aidl_return = HistogramErrorCode::NONE;
299 return ndk::ScopedAStatus::ok();
300 }
301
getPanelCalibrationStatus(PanelCalibrationStatus * _aidl_return)302 ndk::ScopedAStatus Display::getPanelCalibrationStatus(PanelCalibrationStatus *_aidl_return){
303 if (mDisplay) {
304 *_aidl_return = mDisplay->getPanelCalibrationStatus();
305 return ndk::ScopedAStatus::ok();
306 }
307 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
308 }
309
isDbmSupported(bool * _aidl_return)310 ndk::ScopedAStatus Display::isDbmSupported(bool *_aidl_return) {
311 if (!mDisplay) {
312 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
313 }
314 *_aidl_return = mDisplay->isDbmSupported();
315 return ndk::ScopedAStatus::ok();
316 }
317
setDbmState(bool enabled)318 ndk::ScopedAStatus Display::setDbmState(bool enabled) {
319 if (!mDisplay) {
320 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
321 }
322 mDisplay->setDbmState(enabled);
323 return ndk::ScopedAStatus::ok();
324 }
325
getHistogramCapability(HistogramCapability * _aidl_return)326 ndk::ScopedAStatus Display::getHistogramCapability(HistogramCapability *_aidl_return) {
327 if (mDisplay && mDisplay->mHistogramController) {
328 return mDisplay->mHistogramController->getHistogramCapability(_aidl_return);
329 }
330 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
331 }
332
registerHistogram(const ndk::SpAIBinder & token,const HistogramConfig & histogramConfig,HistogramErrorCode * _aidl_return)333 ndk::ScopedAStatus Display::registerHistogram(const ndk::SpAIBinder &token,
334 const HistogramConfig &histogramConfig,
335 HistogramErrorCode *_aidl_return) {
336 if (mDisplay && mDisplay->mHistogramController) {
337 return mDisplay->mHistogramController->registerHistogram(token, histogramConfig,
338 _aidl_return);
339 }
340 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
341 }
342
queryHistogram(const ndk::SpAIBinder & token,std::vector<char16_t> * histogramBuffer,HistogramErrorCode * _aidl_return)343 ndk::ScopedAStatus Display::queryHistogram(const ndk::SpAIBinder &token,
344 std::vector<char16_t> *histogramBuffer,
345 HistogramErrorCode *_aidl_return) {
346 if (mDisplay && mDisplay->mHistogramController) {
347 return mDisplay->mHistogramController->queryHistogram(token, histogramBuffer, _aidl_return);
348 }
349 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
350 }
351
reconfigHistogram(const ndk::SpAIBinder & token,const HistogramConfig & histogramConfig,HistogramErrorCode * _aidl_return)352 ndk::ScopedAStatus Display::reconfigHistogram(const ndk::SpAIBinder &token,
353 const HistogramConfig &histogramConfig,
354 HistogramErrorCode *_aidl_return) {
355 if (mDisplay && mDisplay->mHistogramController) {
356 return mDisplay->mHistogramController->reconfigHistogram(token, histogramConfig,
357 _aidl_return);
358 }
359 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
360 }
361
unregisterHistogram(const ndk::SpAIBinder & token,HistogramErrorCode * _aidl_return)362 ndk::ScopedAStatus Display::unregisterHistogram(const ndk::SpAIBinder &token,
363 HistogramErrorCode *_aidl_return) {
364 if (mDisplay && mDisplay->mHistogramController) {
365 return mDisplay->mHistogramController->unregisterHistogram(token, _aidl_return);
366 }
367 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
368 }
369
setFixedTe2Rate(int rateHz,int * _aidl_return)370 ndk::ScopedAStatus Display::setFixedTe2Rate(int rateHz, int* _aidl_return) {
371 if (mDisplay) {
372 *_aidl_return = mDisplay->setFixedTe2Rate(rateHz);
373 return ndk::ScopedAStatus::ok();
374 }
375 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
376 }
377
queryStats(DisplayStats::Tag tag,std::optional<DisplayStats> * _aidl_return)378 ndk::ScopedAStatus Display::queryStats(DisplayStats::Tag tag,
379 std::optional<DisplayStats>* _aidl_return) {
380 ATRACE_NAME(
381 String8::format("%s(%s)", __func__,
382 aidl::com::google::hardware::pixel::display::toString(tag).c_str()));
383 if (!mDisplay) {
384 ALOGW("%s: mDisplay is NULL", __func__);
385 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
386 }
387 switch (tag) {
388 case DisplayStats::brightnessNits:
389 if (mDisplay->mBrightnessController != nullptr) {
390 auto res = mDisplay->mBrightnessController->getBrightnessNitsAndMode();
391 if (res != std::nullopt) {
392 double nits = std::get<float>(res.value());
393 (*_aidl_return) = DisplayStats::make<DisplayStats::brightnessNits>(nits);
394 } else {
395 ALOGW("%s: getBrightnessNitsAndMode returned nullopt!", __func__);
396 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
397 }
398 } else {
399 ALOGW("%s: mBrightnessController is null!", __func__);
400 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
401 }
402 break;
403 case DisplayStats::brightnessDbv:
404 if (mDisplay->mBrightnessController != nullptr) {
405 int dbv = mDisplay->mBrightnessController->getBrightnessLevel();
406 (*_aidl_return) = DisplayStats::make<DisplayStats::brightnessDbv>(dbv);
407 } else {
408 ALOGW("%s: mBrightnessController is null!", __func__);
409 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
410 }
411 break;
412 case DisplayStats::operationRate:
413 if (mDisplay->isOperationRateSupported()) {
414 int op_hz = mDisplay->mOperationRateManager->getTargetOperationRate();
415 (*_aidl_return) = DisplayStats::make<DisplayStats::operationRate>(op_hz);
416 } else {
417 ALOGW("%s: operation rate not supported!", __func__);
418 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
419 }
420 break;
421 case DisplayStats::opr:
422 if (mDisplay->mHistogramController) {
423 std::array<double, HistogramController::kOPRConfigsCount> oprVals;
424 ndk::ScopedAStatus status = mDisplay->mHistogramController->queryOPR(oprVals);
425 if (!status.isOk()) return status;
426 (*_aidl_return) = DisplayStats::make<DisplayStats::opr>(oprVals);
427 } else {
428 ALOGW("%s: mHistogramController is null!", __func__);
429 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
430 }
431 break;
432 default:
433 ALOGW("%s: invalid stats tag: %u", __func__, (uint32_t)tag);
434 *_aidl_return = std::nullopt;
435 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
436 };
437 return ndk::ScopedAStatus::ok();
438 }
439
440 } // namespace display
441 } // namespace pixel
442 } // namespace hardware
443 } // namespace google
444 } // namespace com
445 } // namespace aidl
446