1 /*
2 * Copyright (C) 2020 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 "BrightnessController.h"
18 #include "ExynosDisplayDrmInterfaceModule.h"
19 #include "ExynosPrimaryDisplayModule.h"
20 #include <drm/samsung_drm.h>
21
22 using BrightnessRange = BrightnessController::BrightnessRange;
23
24 using namespace gs101;
25
26 /////////////////////////////////////////////////// ExynosDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)27 ExynosDisplayDrmInterfaceModule::ExynosDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
28 : ExynosDisplayDrmInterface(exynosDisplay)
29 {
30 }
31
~ExynosDisplayDrmInterfaceModule()32 ExynosDisplayDrmInterfaceModule::~ExynosDisplayDrmInterfaceModule()
33 {
34 }
35
parseBpcEnums(const DrmProperty & property)36 void ExynosDisplayDrmInterfaceModule::parseBpcEnums(const DrmProperty& property)
37 {
38 const std::vector<std::pair<uint32_t, const char *>> bpcEnums = {
39 {static_cast<uint32_t>(BPC_UNSPECIFIED), "Unspecified"},
40 {static_cast<uint32_t>(BPC_8), "8bpc"},
41 {static_cast<uint32_t>(BPC_10), "10bpc"},
42 };
43
44 ALOGD("Init bpc enums");
45 DrmEnumParser::parseEnums(property, bpcEnums, mBpcEnums);
46 for (auto &e : mBpcEnums) {
47 ALOGD("bpc [bpc: %d, drm: %" PRId64 "]", e.first, e.second);
48 }
49 }
50
initDrmDevice(DrmDevice * drmDevice)51 int32_t ExynosDisplayDrmInterfaceModule::initDrmDevice(DrmDevice *drmDevice)
52 {
53 int ret = NO_ERROR;
54 if ((ret = ExynosDisplayDrmInterface::initDrmDevice(drmDevice)) != NO_ERROR)
55 return ret;
56
57 mOldDqeBlobs.init(drmDevice);
58
59 initOldDppBlobs(drmDevice);
60 if (mDrmCrtc->force_bpc_property().id())
61 parseBpcEnums(mDrmCrtc->force_bpc_property());
62
63 mOldHistoBlobs.init(drmDevice);
64
65 return ret;
66 }
67
destroyOldBlobs(std::vector<uint32_t> & oldBlobs)68 void ExynosDisplayDrmInterfaceModule::destroyOldBlobs(
69 std::vector<uint32_t> &oldBlobs)
70 {
71 for (auto &blob : oldBlobs) {
72 mDrmDevice->DestroyPropertyBlob(blob);
73 }
74 oldBlobs.clear();
75 }
76
77 template<typename StageDataType>
setDisplayColorBlob(const DrmProperty & prop,const uint32_t type,const StageDataType & stage,const typename GsInterfaceType::IDqe & dqe,ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)78 int32_t ExynosDisplayDrmInterfaceModule::setDisplayColorBlob(
79 const DrmProperty &prop,
80 const uint32_t type,
81 const StageDataType &stage,
82 const typename GsInterfaceType::IDqe &dqe,
83 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq)
84 {
85 /* dirty bit is valid only if enable is true */
86 if (!prop.id())
87 return NO_ERROR;
88 if (!mForceDisplayColorSetting && stage.enable && !stage.dirty)
89 return NO_ERROR;
90
91 int32_t ret = 0;
92 uint32_t blobId = 0;
93 uint64_t lutSize;
94
95 if (stage.enable) {
96 switch (type) {
97 case DqeBlobs::CGC:
98 ret = gs::ColorDrmBlobFactory::cgc(dqe.Cgc().config, mDrmDevice, blobId);
99 break;
100 case DqeBlobs::DEGAMMA_LUT:
101 std::tie(ret, lutSize) = mDrmCrtc->degamma_lut_size_property().value();
102 if (ret < 0) {
103 HWC_LOGE(mExynosDisplay, "%s: there is no degamma_lut_size (ret = %d)",
104 __func__, ret);
105 } else {
106 ret = gs::ColorDrmBlobFactory::degamma(lutSize, dqe.DegammaLut().config,
107 mDrmDevice, blobId);
108 }
109 break;
110 case DqeBlobs::REGAMMA_LUT:
111 std::tie(ret, lutSize) = mDrmCrtc->gamma_lut_size_property().value();
112 if (ret < 0) {
113 HWC_LOGE(mExynosDisplay, "%s: there is no gamma_lut_size (ret = %d)", __func__,
114 ret);
115 } else {
116 ret = gs::ColorDrmBlobFactory::regamma(lutSize, dqe.RegammaLut().config,
117 mDrmDevice, blobId);
118 }
119 break;
120 case DqeBlobs::GAMMA_MAT:
121 ret = gs::ColorDrmBlobFactory::gammaMatrix(dqe.GammaMatrix().config, mDrmDevice,
122 blobId);
123 break;
124 case DqeBlobs::LINEAR_MAT:
125 ret = gs::ColorDrmBlobFactory::linearMatrix(dqe.LinearMatrix().config, mDrmDevice,
126 blobId);
127 break;
128 case DqeBlobs::DISP_DITHER:
129 ret = gs::ColorDrmBlobFactory::displayDither(dqe.DqeControl().config, mDrmDevice,
130 blobId);
131 break;
132 case DqeBlobs::CGC_DITHER:
133 ret = gs::ColorDrmBlobFactory::cgcDither(dqe.DqeControl().config, mDrmDevice, blobId);
134 break;
135 default:
136 ret = -EINVAL;
137 }
138 if (ret != NO_ERROR) {
139 HWC_LOGE(mExynosDisplay, "%s: create blob fail", __func__);
140 return ret;
141 }
142 }
143
144 /* Skip setting when previous and current setting is same with 0 */
145 if ((blobId == 0) && (mOldDqeBlobs.getBlob(type) == 0))
146 return ret;
147
148 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, blobId)) < 0) {
149 HWC_LOGE(mExynosDisplay, "%s: Fail to set property",
150 __func__);
151 return ret;
152 }
153 mOldDqeBlobs.addBlob(type, blobId);
154
155 // disp_dither and cgc dither are part of DqeCtrl stage and the notification
156 // will be sent after all data in DqeCtrl stage are applied.
157 if (type != DqeBlobs::DISP_DITHER && type != DqeBlobs::CGC_DITHER)
158 stage.NotifyDataApplied();
159
160 return ret;
161 }
162
setDisplayColorSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)163 int32_t ExynosDisplayDrmInterfaceModule::setDisplayColorSetting(
164 ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq) {
165 if (!mForceDisplayColorSetting && !mColorSettingChanged)
166 return NO_ERROR;
167
168 ExynosDeviceModule* device = static_cast<ExynosDeviceModule*>(mExynosDisplay->mDevice);
169 gs101::ColorManager* colorManager = device->getDisplayColorManager(mExynosDisplay);
170
171 int ret = NO_ERROR;
172 const typename GsInterfaceType::IDqe& dqe = colorManager->getDqe();
173
174 if ((mDrmCrtc->cgc_lut_property().id() != 0) &&
175 (ret = setDisplayColorBlob(mDrmCrtc->cgc_lut_property(),
176 static_cast<uint32_t>(DqeBlobs::CGC),
177 dqe.Cgc(), dqe, drmReq) != NO_ERROR)) {
178 HWC_LOGE(mExynosDisplay, "%s: set Cgc blob fail", __func__);
179 return ret;
180 }
181 if ((ret = setDisplayColorBlob(mDrmCrtc->degamma_lut_property(),
182 static_cast<uint32_t>(DqeBlobs::DEGAMMA_LUT),
183 dqe.DegammaLut(), dqe, drmReq) != NO_ERROR)) {
184 HWC_LOGE(mExynosDisplay, "%s: set DegammaLut blob fail", __func__);
185 return ret;
186 }
187 if ((ret = setDisplayColorBlob(mDrmCrtc->gamma_lut_property(),
188 static_cast<uint32_t>(DqeBlobs::REGAMMA_LUT),
189 dqe.RegammaLut(), dqe, drmReq) != NO_ERROR)) {
190 HWC_LOGE(mExynosDisplay, "%s: set RegammaLut blob fail", __func__);
191 return ret;
192 }
193 if ((ret = setDisplayColorBlob(mDrmCrtc->gamma_matrix_property(),
194 static_cast<uint32_t>(DqeBlobs::GAMMA_MAT),
195 dqe.GammaMatrix(), dqe, drmReq) != NO_ERROR)) {
196 HWC_LOGE(mExynosDisplay, "%s: set GammaMatrix blob fail", __func__);
197 return ret;
198 }
199 if ((ret = setDisplayColorBlob(mDrmCrtc->linear_matrix_property(),
200 static_cast<uint32_t>(DqeBlobs::LINEAR_MAT),
201 dqe.LinearMatrix(), dqe, drmReq) != NO_ERROR)) {
202 HWC_LOGE(mExynosDisplay, "%s: set LinearMatrix blob fail", __func__);
203 return ret;
204 }
205 if ((ret = setDisplayColorBlob(mDrmCrtc->disp_dither_property(),
206 static_cast<uint32_t>(DqeBlobs::DISP_DITHER),
207 dqe.DqeControl(), dqe, drmReq) != NO_ERROR)) {
208 HWC_LOGE(mExynosDisplay, "%s: set DispDither blob fail", __func__);
209 return ret;
210 }
211 if ((ret = setDisplayColorBlob(mDrmCrtc->cgc_dither_property(),
212 static_cast<uint32_t>(DqeBlobs::CGC_DITHER),
213 dqe.DqeControl(), dqe, drmReq) != NO_ERROR)) {
214 HWC_LOGE(mExynosDisplay, "%s: set CgcDither blob fail", __func__);
215 return ret;
216 }
217
218 const DrmProperty &prop_force_bpc = mDrmCrtc->force_bpc_property();
219 if (prop_force_bpc.id()) {
220 uint32_t bpc = static_cast<uint32_t>(BPC_UNSPECIFIED);
221 if (dqe.DqeControl().enable) {
222 if (dqe.DqeControl().config->force_10bpc)
223 bpc = static_cast<uint32_t>(BPC_10);
224 }
225 auto [bpcEnum, ret] = DrmEnumParser::halToDrmEnum(bpc, mBpcEnums);
226 if (ret < 0) {
227 HWC_LOGE(mExynosDisplay, "Fail to convert bpc(%d)", bpc);
228 } else {
229 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop_force_bpc,
230 bpcEnum, true)) < 0) {
231 HWC_LOGE(mExynosDisplay, "%s: Fail to set force bpc property",
232 __func__);
233 }
234 }
235 }
236 dqe.DqeControl().NotifyDataApplied();
237
238 return NO_ERROR;
239 }
240
241 template<typename StageDataType>
setPlaneColorBlob(const std::unique_ptr<DrmPlane> & plane,const DrmProperty & prop,const uint32_t type,const StageDataType & stage,const typename GsInterfaceType::IDpp & dpp,const uint32_t dppIndex,ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,bool forceUpdate)242 int32_t ExynosDisplayDrmInterfaceModule::setPlaneColorBlob(
243 const std::unique_ptr<DrmPlane> &plane,
244 const DrmProperty &prop,
245 const uint32_t type,
246 const StageDataType &stage,
247 const typename GsInterfaceType::IDpp &dpp,
248 const uint32_t dppIndex,
249 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
250 bool forceUpdate)
251 {
252 /* dirty bit is valid only if enable is true */
253 if (!prop.id() || (stage.enable && !stage.dirty && !forceUpdate))
254 return NO_ERROR;
255
256 uint32_t ix = 0;
257 for (;ix < mOldDppBlobs.size(); ix++) {
258 if (mOldDppBlobs[ix].planeId == plane->id()) {
259 break;
260 }
261 }
262 if (ix >= mOldDppBlobs.size()) {
263 HWC_LOGE(mExynosDisplay, "%s: could not find plane %d", __func__, plane->id());
264 return -EINVAL;
265 }
266 DppBlobs &oldDppBlobs = mOldDppBlobs[ix];
267
268 int32_t ret = 0;
269 uint32_t blobId = 0;
270
271 if (stage.enable) {
272 switch (type) {
273 case DppBlobs::EOTF:
274 ret = gs::ColorDrmBlobFactory::eotf(dpp.EotfLut().config, mDrmDevice, blobId);
275 break;
276 case DppBlobs::GM:
277 ret = gs::ColorDrmBlobFactory::gm(dpp.Gm().config, mDrmDevice, blobId);
278 break;
279 case DppBlobs::DTM:
280 ret = gs::ColorDrmBlobFactory::dtm(dpp.Dtm().config, mDrmDevice, blobId);
281 break;
282 case DppBlobs::OETF:
283 ret = gs::ColorDrmBlobFactory::oetf(dpp.OetfLut().config, mDrmDevice, blobId);
284 break;
285 default:
286 ret = -EINVAL;
287 }
288 if (ret != NO_ERROR) {
289 HWC_LOGE(mExynosDisplay, "%s: create blob fail", __func__);
290 return ret;
291 }
292 }
293
294 /* Skip setting when previous and current setting is same with 0 */
295 if ((blobId == 0) && (oldDppBlobs.getBlob(type) == 0) && !forceUpdate)
296 return ret;
297
298 if ((ret = drmReq.atomicAddProperty(plane->id(), prop, blobId)) < 0) {
299 HWC_LOGE(mExynosDisplay, "%s: Fail to set property",
300 __func__);
301 return ret;
302 }
303
304 oldDppBlobs.addBlob(type, blobId);
305 stage.NotifyDataApplied();
306
307 return ret;
308 }
309
setPlaneColorSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,const std::unique_ptr<DrmPlane> & plane,const exynos_win_config_data & config,uint32_t & solidColor)310 int32_t ExynosDisplayDrmInterfaceModule::setPlaneColorSetting(
311 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
312 const std::unique_ptr<DrmPlane> &plane,
313 const exynos_win_config_data &config, uint32_t &solidColor)
314 {
315 if (mColorSettingChanged == false) return NO_ERROR;
316
317 if ((config.assignedMPP == nullptr) ||
318 (config.assignedMPP->mAssignedSources.size() == 0)) {
319 HWC_LOGE(mExynosDisplay, "%s:: config's mpp source size is invalid",
320 __func__);
321 return -EINVAL;
322 }
323 ExynosMPPSource* mppSource = config.assignedMPP->mAssignedSources[0];
324 if (mppSource->mSourceType >= MPP_SOURCE_MAX) {
325 HWC_LOGE(mExynosDisplay,
326 "%s: invalid mpp source type (%d)", __func__, mppSource->mSourceType);
327 return -EINVAL;
328 }
329
330 ExynosDeviceModule* device = static_cast<ExynosDeviceModule*>(mExynosDisplay->mDevice);
331 ColorManager* colorManager = device->getDisplayColorManager(mExynosDisplay);
332 if (!colorManager) {
333 HWC_LOGE(mExynosDisplay, "%s: no colorManager for this display", __func__);
334 return -EINVAL;
335 }
336
337 /*
338 * Color conversion of Client and Exynos composition buffer
339 * is already addressed by GLES or G2D. But as of now, 'dim SDR' is only
340 * supported by HWC/displaycolor, we need put client composition under
341 * control of HWC/displaycolor.
342 */
343 if (!colorManager->hasDppForLayer(mppSource)) {
344 if (mppSource->mSourceType == MPP_SOURCE_LAYER) {
345 HWC_LOGE(mExynosDisplay,
346 "%s: layer need color conversion but there is no IDpp",
347 __func__);
348 return -EINVAL;
349 } else if (mppSource->mSourceType == MPP_SOURCE_COMPOSITION_TARGET) {
350 return NO_ERROR;
351 } else {
352 HWC_LOGE(mExynosDisplay,
353 "%s: invalid mpp source type (%d)", __func__, mppSource->mSourceType);
354 return -EINVAL;
355 }
356 }
357
358 if (mppSource->mSourceType == MPP_SOURCE_LAYER) {
359 ExynosLayer* layer = (ExynosLayer*)mppSource;
360
361 /* color conversion was already handled by m2mMPP */
362 if ((layer->mM2mMPP != nullptr) &&
363 (layer->mSrcImg.dataSpace != layer->mMidImg.dataSpace)) {
364 return NO_ERROR;
365 }
366 }
367
368 const typename GsInterfaceType::IDpp& dpp = colorManager->getDppForLayer(mppSource);
369 const uint32_t dppIndex = static_cast<uint32_t>(colorManager->getDppIndexForLayer(mppSource));
370 bool planeChanged = colorManager->checkAndSaveLayerPlaneId(mppSource, plane->id());
371
372 auto &color = dpp.SolidColor();
373 // exynos_win_config_data.color ARGB
374 solidColor = (color.a << 24) | (color.r << 16) | (color.g << 8) | color.b;
375
376 int ret = 0;
377 if ((ret = setPlaneColorBlob(plane, plane->eotf_lut_property(),
378 static_cast<uint32_t>(DppBlobs::EOTF),
379 dpp.EotfLut(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
380 HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set oetf blob fail",
381 __func__, dppIndex);
382 return ret;
383 }
384 if ((ret = setPlaneColorBlob(plane, plane->gammut_matrix_property(),
385 static_cast<uint32_t>(DppBlobs::GM),
386 dpp.Gm(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
387 HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set GM blob fail",
388 __func__, dppIndex);
389 return ret;
390 }
391 if ((ret = setPlaneColorBlob(plane, plane->tone_mapping_property(),
392 static_cast<uint32_t>(DppBlobs::DTM),
393 dpp.Dtm(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
394 HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set DTM blob fail",
395 __func__, dppIndex);
396 return ret;
397 }
398 if ((ret = setPlaneColorBlob(plane, plane->oetf_lut_property(),
399 static_cast<uint32_t>(DppBlobs::OETF),
400 dpp.OetfLut(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
401 HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set OETF blob fail",
402 __func__, dppIndex);
403 return ret;
404 }
405
406 return 0;
407 }
408
~SaveBlob()409 ExynosDisplayDrmInterfaceModule::SaveBlob::~SaveBlob() {
410 clearBlobs();
411 }
412
clearBlobs()413 void ExynosDisplayDrmInterfaceModule::SaveBlob::clearBlobs() {
414 for (auto &it: blobs) {
415 mDrmDevice->DestroyPropertyBlob(it);
416 }
417 blobs.clear();
418 }
419
addBlob(uint32_t type,uint32_t blob)420 void ExynosDisplayDrmInterfaceModule::SaveBlob::addBlob(
421 uint32_t type, uint32_t blob)
422 {
423 if (type >= blobs.size()) {
424 ALOGE("Invalid dqe blop type: %d", type);
425 return;
426 }
427 if (blobs[type] > 0)
428 mDrmDevice->DestroyPropertyBlob(blobs[type]);
429
430 blobs[type] = blob;
431 }
432
getBlob(uint32_t type)433 uint32_t ExynosDisplayDrmInterfaceModule::SaveBlob::getBlob(uint32_t type)
434 {
435 if (type >= blobs.size()) {
436 ALOGE("Invalid dqe blop type: %d", type);
437 return 0;
438 }
439 return blobs[type];
440 }
441
getDisplayInfo(std::vector<displaycolor::DisplayInfo> & display_info)442 void ExynosDisplayDrmInterfaceModule::getDisplayInfo(
443 std::vector<displaycolor::DisplayInfo> &display_info) {
444 displaycolor::DisplayInfo disp_info;
445
446 if (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY) {
447 disp_info.brightness_ranges = mExynosDisplay->mBrightnessController->getBrightnessRanges();
448 disp_info.panel_name = GetPanelName();
449 disp_info.panel_serial = GetPanelSerial();
450 if (mExynosDisplay->mIndex == 0)
451 disp_info.display_type = DisplayType::DISPLAY_PRIMARY;
452 else
453 disp_info.display_type = DisplayType::DISPLAY_SECONDARY;
454 } else if (mExynosDisplay->mType == HWC_DISPLAY_EXTERNAL) {
455 disp_info.display_type = DisplayType::DISPLAY_EXTERNAL;
456 disp_info.panel_name = "external_display";
457 disp_info.panel_serial = "0001";
458 } else {
459 ALOGE("Unsupported display type (%d) in getDisplayInfo!", mExynosDisplay->mType);
460 return;
461 }
462
463 display_info.push_back(disp_info);
464 }
465
GetPanelInfo(const std::string & sysfs_rel,char delim)466 const std::string ExynosDisplayDrmInterfaceModule::GetPanelInfo(const std::string &sysfs_rel,
467 char delim) {
468 ExynosPrimaryDisplayModule* display = (ExynosPrimaryDisplayModule*)mExynosDisplay;
469 const std::string& sysfs = display->getPanelSysfsPath();
470
471 if (sysfs.empty()) {
472 return "";
473 }
474
475 std::string info;
476 if (readLineFromFile(sysfs + "/" + sysfs_rel, info, delim) != OK) {
477 ALOGE("failed reading %s/%s", sysfs.c_str(), sysfs_rel.c_str());
478 return "";
479 }
480
481 return info;
482 }
483
484 /* For Histogram */
createHistoRoiBlob(uint32_t & blobId)485 int32_t ExynosDisplayDrmInterfaceModule::createHistoRoiBlob(uint32_t &blobId) {
486 struct histogram_roi histo_roi;
487
488 std::unique_lock<std::mutex> lk((mHistogramInfo->mSetHistInfoMutex));
489 histo_roi.start_x = mHistogramInfo->getHistogramROI().start_x;
490 histo_roi.start_y = mHistogramInfo->getHistogramROI().start_y;
491 histo_roi.hsize = mHistogramInfo->getHistogramROI().hsize;
492 histo_roi.vsize = mHistogramInfo->getHistogramROI().vsize;
493
494 int ret = mDrmDevice->CreatePropertyBlob(&histo_roi, sizeof(histo_roi), &blobId);
495 if (ret) {
496 HWC_LOGE(mExynosDisplay, "Failed to create histogram roi blob %d", ret);
497 return ret;
498 }
499
500 return NO_ERROR;
501 }
502
createHistoWeightsBlob(uint32_t & blobId)503 int32_t ExynosDisplayDrmInterfaceModule::createHistoWeightsBlob(uint32_t &blobId) {
504 struct histogram_weights histo_weights;
505
506 std::unique_lock<std::mutex> lk((mHistogramInfo->mSetHistInfoMutex));
507 histo_weights.weight_r = mHistogramInfo->getHistogramWeights().weight_r;
508 histo_weights.weight_g = mHistogramInfo->getHistogramWeights().weight_g;
509 histo_weights.weight_b = mHistogramInfo->getHistogramWeights().weight_b;
510
511 int ret = mDrmDevice->CreatePropertyBlob(&histo_weights, sizeof(histo_weights), &blobId);
512 if (ret) {
513 HWC_LOGE(mExynosDisplay, "Failed to create histogram weights blob %d", ret);
514 return ret;
515 }
516
517 return NO_ERROR;
518 }
519
setDisplayHistoBlob(const DrmProperty & prop,const uint32_t type,ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)520 int32_t ExynosDisplayDrmInterfaceModule::setDisplayHistoBlob(
521 const DrmProperty &prop, const uint32_t type,
522 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) {
523 if (!prop.id()) return NO_ERROR;
524
525 int32_t ret = NO_ERROR;
526 uint32_t blobId = 0;
527
528 switch (type) {
529 case HistoBlobs::ROI:
530 ret = createHistoRoiBlob(blobId);
531 break;
532 case HistoBlobs::WEIGHTS:
533 ret = createHistoWeightsBlob(blobId);
534 break;
535 default:
536 ret = -EINVAL;
537 }
538 if (ret != NO_ERROR) {
539 HWC_LOGE(mExynosDisplay, "%s: Failed to create blob", __func__);
540 return ret;
541 }
542
543 /* Skip setting when previous and current setting is same with 0 */
544 if ((blobId == 0) && (mOldHistoBlobs.getBlob(type) == 0)) return ret;
545
546 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, blobId)) < 0) {
547 HWC_LOGE(mExynosDisplay, "%s: Failed to add property", __func__);
548 return ret;
549 }
550 mOldHistoBlobs.addBlob(type, blobId);
551
552 return ret;
553 }
554
setDisplayHistogramSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)555 int32_t ExynosDisplayDrmInterfaceModule::setDisplayHistogramSetting(
556 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) {
557 if ((isHistogramInfoRegistered() == false) || (isPrimary() == false)) return NO_ERROR;
558
559 int ret = NO_ERROR;
560
561 if ((ret = setDisplayHistoBlob(mDrmCrtc->histogram_roi_property(),
562 static_cast<uint32_t>(HistoBlobs::ROI), drmReq) != NO_ERROR)) {
563 HWC_LOGE(mExynosDisplay, "%s: Failed to set Histo_ROI blob", __func__);
564 return ret;
565 }
566 if ((ret = setDisplayHistoBlob(mDrmCrtc->histogram_weights_property(),
567 static_cast<uint32_t>(HistoBlobs::WEIGHTS),
568 drmReq) != NO_ERROR)) {
569 HWC_LOGE(mExynosDisplay, "%s: Failed to set Histo_Weights blob", __func__);
570 return ret;
571 }
572
573 const DrmProperty &prop_histo_threshold = mDrmCrtc->histogram_threshold_property();
574 if (prop_histo_threshold.id()) {
575 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop_histo_threshold,
576 (uint64_t)(mHistogramInfo->getHistogramThreshold()),
577 true)) < 0) {
578 HWC_LOGE(mExynosDisplay, "%s: Failed to set histogram thereshold property", __func__);
579 return ret;
580 }
581 }
582
583 return NO_ERROR;
584 }
585
setHistogramControl(hidl_histogram_control_t control)586 int32_t ExynosDisplayDrmInterfaceModule::setHistogramControl(hidl_histogram_control_t control) {
587 if ((isHistogramInfoRegistered() == false) || (isPrimary() == false)) return NO_ERROR;
588
589 int ret = NO_ERROR;
590 uint32_t crtc_id = mDrmCrtc->id();
591
592 if (control == hidl_histogram_control_t::HISTOGRAM_CONTROL_REQUEST) {
593 ret = mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_HISTOGRAM_REQUEST, (void *)&crtc_id);
594 } else if (control == hidl_histogram_control_t::HISTOGRAM_CONTROL_CANCEL) {
595 ret = mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_HISTOGRAM_CANCEL, (void *)&crtc_id);
596 }
597
598 return ret;
599 }
600
setHistogramData(void * bin)601 int32_t ExynosDisplayDrmInterfaceModule::setHistogramData(void *bin) {
602 if (!bin) return -EINVAL;
603
604 /*
605 * There are two handling methods.
606 * For ContentSampling in HWC_2.3 API, histogram bin needs to be accumulated.
607 * For Histogram IDL, histogram bin need to be sent to IDL block.
608 */
609 if (mHistogramInfo->getHistogramType() == HistogramInfo::HistogramType::HISTOGRAM_HIDL) {
610 (mHistogramInfo.get())->callbackHistogram((char16_t *)bin);
611 } else {
612 /*
613 * ContentSampling in HWC2.3 API is not supported
614 */
615 return -ENOTSUP;
616 }
617
618 return NO_ERROR;
619 }
620
621 //////////////////////////////////////////////////// ExynosPrimaryDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosPrimaryDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)622 ExynosPrimaryDisplayDrmInterfaceModule::ExynosPrimaryDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
623 : ExynosDisplayDrmInterfaceModule(exynosDisplay)
624 {
625 }
626
~ExynosPrimaryDisplayDrmInterfaceModule()627 ExynosPrimaryDisplayDrmInterfaceModule::~ExynosPrimaryDisplayDrmInterfaceModule()
628 {
629 }
630
631 //////////////////////////////////////////////////// ExynosExternalDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosExternalDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)632 ExynosExternalDisplayDrmInterfaceModule::ExynosExternalDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
633 : ExynosDisplayDrmInterfaceModule(exynosDisplay)
634 {
635 }
636
~ExynosExternalDisplayDrmInterfaceModule()637 ExynosExternalDisplayDrmInterfaceModule::~ExynosExternalDisplayDrmInterfaceModule()
638 {
639 }
640