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     blobs.clear();
412 }
413 
clearBlobs()414 void ExynosDisplayDrmInterfaceModule::SaveBlob::clearBlobs() {
415     for (size_t i = 0; i < blobs.size(); ++i) {
416         mDrmDevice->DestroyPropertyBlob(blobs[i]);
417         blobs[i] = 0;
418     }
419 }
420 
addBlob(uint32_t type,uint32_t blob)421 void ExynosDisplayDrmInterfaceModule::SaveBlob::addBlob(
422         uint32_t type, uint32_t blob)
423 {
424     if (type >= blobs.size()) {
425         ALOGE("%s: Invalid blob type: %u", mBlobClassName, type);
426         return;
427     }
428     if (blobs[type] > 0)
429         mDrmDevice->DestroyPropertyBlob(blobs[type]);
430 
431     blobs[type] = blob;
432 }
433 
getBlob(uint32_t type)434 uint32_t ExynosDisplayDrmInterfaceModule::SaveBlob::getBlob(uint32_t type)
435 {
436     if (type >= blobs.size()) {
437         ALOGE("%s: Invalid blob type: %u", mBlobClassName, type);
438         return 0;
439     }
440     return blobs[type];
441 }
442 
getDisplayInfo(std::vector<displaycolor::DisplayInfo> & display_info)443 void ExynosDisplayDrmInterfaceModule::getDisplayInfo(
444         std::vector<displaycolor::DisplayInfo> &display_info) {
445     displaycolor::DisplayInfo disp_info;
446 
447     if (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY) {
448         disp_info.brightness_ranges = mExynosDisplay->mBrightnessController->getBrightnessRanges();
449         disp_info.panel_name = GetPanelName();
450         disp_info.panel_serial = GetPanelSerial();
451         if (mExynosDisplay->mIndex == 0)
452             disp_info.display_type = DisplayType::DISPLAY_PRIMARY;
453         else
454             disp_info.display_type = DisplayType::DISPLAY_SECONDARY;
455     } else if (mExynosDisplay->mType == HWC_DISPLAY_EXTERNAL) {
456         disp_info.display_type = DisplayType::DISPLAY_EXTERNAL;
457         disp_info.panel_name = "external_display";
458         disp_info.panel_serial = "0001";
459     } else {
460         ALOGE("Unsupported display type (%d) in getDisplayInfo!", mExynosDisplay->mType);
461         return;
462     }
463 
464     display_info.push_back(disp_info);
465 }
466 
GetPanelInfo(const std::string & sysfs_rel,char delim)467 const std::string ExynosDisplayDrmInterfaceModule::GetPanelInfo(const std::string &sysfs_rel,
468                                                                 char delim) {
469     ExynosPrimaryDisplayModule* display = (ExynosPrimaryDisplayModule*)mExynosDisplay;
470     const std::string& sysfs = display->getPanelSysfsPath();
471 
472     if (sysfs.empty()) {
473         return "";
474     }
475 
476     std::string info;
477     if (readLineFromFile(sysfs + "/" + sysfs_rel, info, delim) != OK) {
478         ALOGE("failed reading %s/%s", sysfs.c_str(), sysfs_rel.c_str());
479         return "";
480     }
481 
482     return info;
483 }
484 
485 /* For Histogram */
createHistoRoiBlob(uint32_t & blobId)486 int32_t ExynosDisplayDrmInterfaceModule::createHistoRoiBlob(uint32_t &blobId) {
487     struct histogram_roi histo_roi;
488 
489     std::unique_lock<std::mutex> lk((mHistogramInfo->mSetHistInfoMutex));
490     histo_roi.start_x = mHistogramInfo->getHistogramROI().start_x;
491     histo_roi.start_y = mHistogramInfo->getHistogramROI().start_y;
492     histo_roi.hsize = mHistogramInfo->getHistogramROI().hsize;
493     histo_roi.vsize = mHistogramInfo->getHistogramROI().vsize;
494 
495     int ret = mDrmDevice->CreatePropertyBlob(&histo_roi, sizeof(histo_roi), &blobId);
496     if (ret) {
497         HWC_LOGE(mExynosDisplay, "Failed to create histogram roi blob %d", ret);
498         return ret;
499     }
500 
501     return NO_ERROR;
502 }
503 
createHistoWeightsBlob(uint32_t & blobId)504 int32_t ExynosDisplayDrmInterfaceModule::createHistoWeightsBlob(uint32_t &blobId) {
505     struct histogram_weights histo_weights;
506 
507     std::unique_lock<std::mutex> lk((mHistogramInfo->mSetHistInfoMutex));
508     histo_weights.weight_r = mHistogramInfo->getHistogramWeights().weight_r;
509     histo_weights.weight_g = mHistogramInfo->getHistogramWeights().weight_g;
510     histo_weights.weight_b = mHistogramInfo->getHistogramWeights().weight_b;
511 
512     int ret = mDrmDevice->CreatePropertyBlob(&histo_weights, sizeof(histo_weights), &blobId);
513     if (ret) {
514         HWC_LOGE(mExynosDisplay, "Failed to create histogram weights blob %d", ret);
515         return ret;
516     }
517 
518     return NO_ERROR;
519 }
520 
setDisplayHistoBlob(const DrmProperty & prop,const uint32_t type,ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)521 int32_t ExynosDisplayDrmInterfaceModule::setDisplayHistoBlob(
522         const DrmProperty &prop, const uint32_t type,
523         ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) {
524     if (!prop.id()) return NO_ERROR;
525 
526     int32_t ret = NO_ERROR;
527     uint32_t blobId = 0;
528 
529     switch (type) {
530         case HistoBlobs::ROI:
531             ret = createHistoRoiBlob(blobId);
532             break;
533         case HistoBlobs::WEIGHTS:
534             ret = createHistoWeightsBlob(blobId);
535             break;
536         default:
537             ret = -EINVAL;
538     }
539     if (ret != NO_ERROR) {
540         HWC_LOGE(mExynosDisplay, "%s: Failed to create blob", __func__);
541         return ret;
542     }
543 
544     /* Skip setting when previous and current setting is same with 0 */
545     if ((blobId == 0) && (mOldHistoBlobs.getBlob(type) == 0)) return ret;
546 
547     if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, blobId)) < 0) {
548         HWC_LOGE(mExynosDisplay, "%s: Failed to add property", __func__);
549         return ret;
550     }
551     mOldHistoBlobs.addBlob(type, blobId);
552 
553     return ret;
554 }
555 
setDisplayHistogramSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)556 int32_t ExynosDisplayDrmInterfaceModule::setDisplayHistogramSetting(
557         ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) {
558     if ((isHistogramInfoRegistered() == false) || (isPrimary() == false)) return NO_ERROR;
559 
560     int ret = NO_ERROR;
561 
562     if ((ret = setDisplayHistoBlob(mDrmCrtc->histogram_roi_property(),
563                                    static_cast<uint32_t>(HistoBlobs::ROI), drmReq) != NO_ERROR)) {
564         HWC_LOGE(mExynosDisplay, "%s: Failed to set Histo_ROI blob", __func__);
565         return ret;
566     }
567     if ((ret = setDisplayHistoBlob(mDrmCrtc->histogram_weights_property(),
568                                    static_cast<uint32_t>(HistoBlobs::WEIGHTS),
569                                    drmReq) != NO_ERROR)) {
570         HWC_LOGE(mExynosDisplay, "%s: Failed to set Histo_Weights blob", __func__);
571         return ret;
572     }
573 
574     const DrmProperty &prop_histo_threshold = mDrmCrtc->histogram_threshold_property();
575     if (prop_histo_threshold.id()) {
576         if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop_histo_threshold,
577                                             (uint64_t)(mHistogramInfo->getHistogramThreshold()),
578                                             true)) < 0) {
579             HWC_LOGE(mExynosDisplay, "%s: Failed to set histogram thereshold property", __func__);
580             return ret;
581         }
582     }
583 
584     return NO_ERROR;
585 }
586 
setHistogramControl(hidl_histogram_control_t control)587 int32_t ExynosDisplayDrmInterfaceModule::setHistogramControl(hidl_histogram_control_t control) {
588     if ((isHistogramInfoRegistered() == false) || (isPrimary() == false)) return NO_ERROR;
589 
590     int ret = NO_ERROR;
591     uint32_t crtc_id = mDrmCrtc->id();
592 
593     if (control == hidl_histogram_control_t::HISTOGRAM_CONTROL_REQUEST) {
594         ret = mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_HISTOGRAM_REQUEST, (void *)&crtc_id);
595     } else if (control == hidl_histogram_control_t::HISTOGRAM_CONTROL_CANCEL) {
596         ret = mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_HISTOGRAM_CANCEL, (void *)&crtc_id);
597     }
598 
599     return ret;
600 }
601 
setHistogramData(void * bin)602 int32_t ExynosDisplayDrmInterfaceModule::setHistogramData(void *bin) {
603     if (!bin) return -EINVAL;
604 
605     /*
606      * There are two handling methods.
607      * For ContentSampling in HWC_2.3 API, histogram bin needs to be accumulated.
608      * For Histogram IDL, histogram bin need to be sent to IDL block.
609      */
610     if (mHistogramInfo->getHistogramType() == HistogramInfo::HistogramType::HISTOGRAM_HIDL) {
611         (mHistogramInfo.get())->callbackHistogram((char16_t *)bin);
612     } else {
613         /*
614          * ContentSampling in HWC2.3 API is not supported
615          */
616         return -ENOTSUP;
617     }
618 
619     return NO_ERROR;
620 }
621 
622 //////////////////////////////////////////////////// ExynosPrimaryDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosPrimaryDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)623 ExynosPrimaryDisplayDrmInterfaceModule::ExynosPrimaryDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
624 : ExynosDisplayDrmInterfaceModule(exynosDisplay)
625 {
626 }
627 
~ExynosPrimaryDisplayDrmInterfaceModule()628 ExynosPrimaryDisplayDrmInterfaceModule::~ExynosPrimaryDisplayDrmInterfaceModule()
629 {
630 }
631 
632 //////////////////////////////////////////////////// ExynosExternalDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosExternalDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)633 ExynosExternalDisplayDrmInterfaceModule::ExynosExternalDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
634 : ExynosDisplayDrmInterfaceModule(exynosDisplay)
635 {
636 }
637 
~ExynosExternalDisplayDrmInterfaceModule()638 ExynosExternalDisplayDrmInterfaceModule::~ExynosExternalDisplayDrmInterfaceModule()
639 {
640 }
641