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