• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 template <typename T, typename M>
convertDqeMatrixDataToMatrix(T & colorMatrix,M & mat,uint32_t dimension)25 int32_t convertDqeMatrixDataToMatrix(T &colorMatrix, M &mat,
26                                      uint32_t dimension) {
27     if (colorMatrix.coeffs.size() != (dimension * dimension)) {
28         HWC_LOGE(nullptr, "Invalid coeff size(%zu)",
29                 colorMatrix.coeffs.size());
30         return -EINVAL;
31     }
32     for (uint32_t i = 0; i < (dimension * dimension); i++) {
33         mat.coeffs[i] = colorMatrix.coeffs[i];
34     }
35 
36     if (colorMatrix.offsets.size() != dimension) {
37         HWC_LOGE(nullptr, "Invalid offset size(%zu)",
38                 colorMatrix.offsets.size());
39         return -EINVAL;
40     }
41     for (uint32_t i = 0; i < dimension; i++) {
42         mat.offsets[i] = colorMatrix.offsets[i];
43     }
44     return NO_ERROR;
45 }
46 
47 using namespace gs101;
48 
49 /////////////////////////////////////////////////// ExynosDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)50 ExynosDisplayDrmInterfaceModule::ExynosDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
51 : ExynosDisplayDrmInterface(exynosDisplay)
52 {
53 }
54 
~ExynosDisplayDrmInterfaceModule()55 ExynosDisplayDrmInterfaceModule::~ExynosDisplayDrmInterfaceModule()
56 {
57 }
58 
parseBpcEnums(const DrmProperty & property)59 void ExynosDisplayDrmInterfaceModule::parseBpcEnums(const DrmProperty& property)
60 {
61     const std::vector<std::pair<uint32_t, const char *>> bpcEnums = {
62         {static_cast<uint32_t>(BPC_UNSPECIFIED), "Unspecified"},
63         {static_cast<uint32_t>(BPC_8), "8bpc"},
64         {static_cast<uint32_t>(BPC_10), "10bpc"},
65     };
66 
67     ALOGD("Init bpc enums");
68     DrmEnumParser::parseEnums(property, bpcEnums, mBpcEnums);
69     for (auto &e : mBpcEnums) {
70         ALOGD("bpc [bpc: %d, drm: %" PRId64 "]", e.first, e.second);
71     }
72 }
73 
initDrmDevice(DrmDevice * drmDevice)74 int32_t ExynosDisplayDrmInterfaceModule::initDrmDevice(DrmDevice *drmDevice)
75 {
76     int ret = NO_ERROR;
77     if ((ret = ExynosDisplayDrmInterface::initDrmDevice(drmDevice)) != NO_ERROR)
78         return ret;
79 
80     if (isPrimary() == false)
81         return ret;
82 
83     mOldDqeBlobs.init(drmDevice);
84 
85     initOldDppBlobs(drmDevice);
86     if (mDrmCrtc->force_bpc_property().id())
87         parseBpcEnums(mDrmCrtc->force_bpc_property());
88 
89     mOldHistoBlobs.init(drmDevice);
90 
91     return ret;
92 }
93 
destroyOldBlobs(std::vector<uint32_t> & oldBlobs)94 void ExynosDisplayDrmInterfaceModule::destroyOldBlobs(
95         std::vector<uint32_t> &oldBlobs)
96 {
97     for (auto &blob : oldBlobs) {
98         mDrmDevice->DestroyPropertyBlob(blob);
99     }
100     oldBlobs.clear();
101 }
102 
createCgcBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)103 int32_t ExynosDisplayDrmInterfaceModule::createCgcBlobFromIDqe(
104         const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
105 {
106     struct cgc_lut cgc;
107     const IDisplayColorGS101::IDqe::CgcData &cgcData = dqe.Cgc();
108 
109     if (cgcData.config == nullptr) {
110         ALOGE("no CGC config");
111         return -EINVAL;
112     }
113 
114     if ((cgcData.config->r_values.size() != DRM_SAMSUNG_CGC_LUT_REG_CNT) ||
115         (cgcData.config->g_values.size() != DRM_SAMSUNG_CGC_LUT_REG_CNT) ||
116         (cgcData.config->b_values.size() != DRM_SAMSUNG_CGC_LUT_REG_CNT)) {
117         ALOGE("CGC data size is not same (r: %zu, g: %zu: b: %zu)",
118                 cgcData.config->r_values.size(),
119                 cgcData.config->g_values.size(),
120                 cgcData.config->b_values.size());
121         return -EINVAL;
122     }
123 
124     for (uint32_t i = 0; i < DRM_SAMSUNG_CGC_LUT_REG_CNT; i++) {
125         cgc.r_values[i] = cgcData.config->r_values[i];
126         cgc.g_values[i] = cgcData.config->g_values[i];
127         cgc.b_values[i] = cgcData.config->b_values[i];
128     }
129     int ret = mDrmDevice->CreatePropertyBlob(&cgc, sizeof(cgc_lut), &blobId);
130     if (ret) {
131         HWC_LOGE(mExynosDisplay, "Failed to create cgc blob %d", ret);
132         return ret;
133     }
134     return NO_ERROR;
135 }
136 
createDegammaLutBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)137 int32_t ExynosDisplayDrmInterfaceModule::createDegammaLutBlobFromIDqe(
138         const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
139 {
140     int ret = 0;
141     uint64_t lut_size = 0;
142 
143     if (dqe.DegammaLut().config == nullptr) {
144         ALOGE("no degamma config");
145         return -EINVAL;
146     }
147 
148     std::tie(ret, lut_size) = mDrmCrtc->degamma_lut_size_property().value();
149     if (ret < 0) {
150          HWC_LOGE(mExynosDisplay, "%s: there is no degamma_lut_size (ret = %d)",
151                  __func__, ret);
152          return ret;
153     }
154     if (lut_size != IDisplayColorGS101::IDqe::DegammaLutData::ConfigType::kLutLen) {
155         HWC_LOGE(mExynosDisplay, "%s: invalid lut size (%" PRId64 ")",
156                 __func__, lut_size);
157         return -EINVAL;
158     }
159 
160     struct drm_color_lut color_lut[IDisplayColorGS101::IDqe::DegammaLutData::ConfigType::kLutLen];
161     for (uint32_t i = 0; i < lut_size; i++) {
162         color_lut[i].red = dqe.DegammaLut().config->values[i];
163     }
164     ret = mDrmDevice->CreatePropertyBlob(color_lut, sizeof(color_lut), &blobId);
165     if (ret) {
166         HWC_LOGE(mExynosDisplay, "Failed to create degamma lut blob %d", ret);
167         return ret;
168     }
169     return NO_ERROR;
170 }
171 
createRegammaLutBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)172 int32_t ExynosDisplayDrmInterfaceModule::createRegammaLutBlobFromIDqe(
173         const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
174 {
175     int ret = 0;
176     uint64_t lut_size = 0;
177 
178     if (dqe.RegammaLut().config == nullptr) {
179         ALOGE("no regamma config");
180         return -EINVAL;
181     }
182 
183     std::tie(ret, lut_size) = mDrmCrtc->gamma_lut_size_property().value();
184     if (ret < 0) {
185          HWC_LOGE(mExynosDisplay, "%s: there is no gamma_lut_size (ret = %d)",
186                  __func__, ret);
187          return ret;
188     }
189     if (lut_size != IDisplayColorGS101::IDqe::DegammaLutData::ConfigType::kLutLen) {
190         HWC_LOGE(mExynosDisplay, "%s: invalid lut size (%" PRId64 ")",
191                 __func__, lut_size);
192         return -EINVAL;
193     }
194 
195     struct drm_color_lut color_lut[IDisplayColorGS101::IDqe::DegammaLutData::ConfigType::kLutLen];
196     for (uint32_t i = 0; i < lut_size; i++) {
197         color_lut[i].red = dqe.RegammaLut().config->r_values[i];
198         color_lut[i].green = dqe.RegammaLut().config->g_values[i];
199         color_lut[i].blue = dqe.RegammaLut().config->b_values[i];
200     }
201     ret = mDrmDevice->CreatePropertyBlob(color_lut, sizeof(color_lut), &blobId);
202     if (ret) {
203         HWC_LOGE(mExynosDisplay, "Failed to create gamma lut blob %d", ret);
204         return ret;
205     }
206     return NO_ERROR;
207 }
208 
createGammaMatBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)209 int32_t ExynosDisplayDrmInterfaceModule::createGammaMatBlobFromIDqe(
210         const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
211 {
212     int ret = 0;
213     struct exynos_matrix gamma_matrix;
214     if ((ret = convertDqeMatrixDataToMatrix(
215                     dqe.GammaMatrix().config->matrix_data, gamma_matrix, DRM_SAMSUNG_MATRIX_DIMENS)) != NO_ERROR)
216     {
217         HWC_LOGE(mExynosDisplay, "Failed to convert gamma matrix");
218         return ret;
219     }
220     ret = mDrmDevice->CreatePropertyBlob(&gamma_matrix, sizeof(gamma_matrix), &blobId);
221     if (ret) {
222         HWC_LOGE(mExynosDisplay, "Failed to create gamma matrix blob %d", ret);
223         return ret;
224     }
225 
226     return NO_ERROR;
227 }
228 
createLinearMatBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)229 int32_t ExynosDisplayDrmInterfaceModule::createLinearMatBlobFromIDqe(
230         const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
231 {
232     int ret = 0;
233     struct exynos_matrix linear_matrix;
234     if ((ret = convertDqeMatrixDataToMatrix(
235                     dqe.LinearMatrix().config->matrix_data, linear_matrix, DRM_SAMSUNG_MATRIX_DIMENS)) != NO_ERROR)
236     {
237         HWC_LOGE(mExynosDisplay, "Failed to convert linear matrix");
238         return ret;
239     }
240     ret = mDrmDevice->CreatePropertyBlob(&linear_matrix, sizeof(linear_matrix), &blobId);
241     if (ret) {
242         HWC_LOGE(mExynosDisplay, "Failed to create linear matrix blob %d", ret);
243         return ret;
244     }
245 
246     return NO_ERROR;
247 }
248 
createDispDitherBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)249 int32_t ExynosDisplayDrmInterfaceModule::createDispDitherBlobFromIDqe(
250         const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
251 {
252     int ret = 0;
253     const IDisplayColorGS101::IDqe::DqeControlData& dqeControl = dqe.DqeControl();
254     if (dqeControl.config->disp_dither_override == false) {
255         blobId = 0;
256         return ret;
257     }
258 
259     ret = mDrmDevice->CreatePropertyBlob((void*)&dqeControl.config->disp_dither_reg,
260             sizeof(dqeControl.config->disp_dither_reg), &blobId);
261     if (ret) {
262         HWC_LOGE(mExynosDisplay, "Failed to create disp dither blob %d", ret);
263         return ret;
264     }
265 
266     return NO_ERROR;
267 }
268 
createCgcDitherBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)269 int32_t ExynosDisplayDrmInterfaceModule::createCgcDitherBlobFromIDqe(
270         const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
271 {
272     int ret = 0;
273     const IDisplayColorGS101::IDqe::DqeControlData& dqeControl = dqe.DqeControl();
274     if (dqeControl.config->cgc_dither_override == false) {
275         blobId = 0;
276         return ret;
277     }
278 
279     ret = mDrmDevice->CreatePropertyBlob((void*)&dqeControl.config->cgc_dither_reg,
280             sizeof(dqeControl.config->cgc_dither_reg), &blobId);
281     if (ret) {
282         HWC_LOGE(mExynosDisplay, "Failed to create disp dither blob %d", ret);
283         return ret;
284     }
285     return NO_ERROR;
286 }
287 
createEotfBlobFromIDpp(const IDisplayColorGS101::IDpp & dpp,uint32_t & blobId)288 int32_t ExynosDisplayDrmInterfaceModule::createEotfBlobFromIDpp(
289         const IDisplayColorGS101::IDpp &dpp, uint32_t &blobId)
290 {
291     struct hdr_eotf_lut eotf_lut;
292 
293     if (dpp.EotfLut().config == nullptr) {
294         ALOGE("no dpp eotf config");
295         return -EINVAL;
296     }
297 
298     if ((dpp.EotfLut().config->tf_data.posx.size() != DRM_SAMSUNG_HDR_EOTF_LUT_LEN) ||
299         (dpp.EotfLut().config->tf_data.posy.size() != DRM_SAMSUNG_HDR_EOTF_LUT_LEN)) {
300         HWC_LOGE(mExynosDisplay, "%s: eotf pos size (%zu, %zu)",
301                 __func__, dpp.EotfLut().config->tf_data.posx.size(),
302                 dpp.EotfLut().config->tf_data.posy.size());
303         return -EINVAL;
304     }
305 
306     for (uint32_t i = 0; i < DRM_SAMSUNG_HDR_EOTF_LUT_LEN; i++) {
307         eotf_lut.posx[i] = dpp.EotfLut().config->tf_data.posx[i];
308         eotf_lut.posy[i] = dpp.EotfLut().config->tf_data.posy[i];
309     }
310     int ret = mDrmDevice->CreatePropertyBlob(&eotf_lut, sizeof(eotf_lut), &blobId);
311     if (ret) {
312         HWC_LOGE(mExynosDisplay, "Failed to create eotf lut blob %d", ret);
313         return ret;
314     }
315     return NO_ERROR;
316 }
317 
createGmBlobFromIDpp(const IDisplayColorGS101::IDpp & dpp,uint32_t & blobId)318 int32_t ExynosDisplayDrmInterfaceModule::createGmBlobFromIDpp(
319         const IDisplayColorGS101::IDpp &dpp, uint32_t &blobId)
320 {
321     int ret = 0;
322     struct hdr_gm_data gm_matrix;
323 
324     if (dpp.Gm().config == nullptr) {
325         ALOGE("no dpp GM config");
326         return -EINVAL;
327     }
328 
329     if ((ret = convertDqeMatrixDataToMatrix(dpp.Gm().config->matrix_data, gm_matrix,
330                                             DRM_SAMSUNG_HDR_GM_DIMENS)) != NO_ERROR)
331     {
332         HWC_LOGE(mExynosDisplay, "Failed to convert gm matrix");
333         return ret;
334     }
335     ret = mDrmDevice->CreatePropertyBlob(&gm_matrix, sizeof(gm_matrix), &blobId);
336     if (ret) {
337         HWC_LOGE(mExynosDisplay, "Failed to create gm matrix blob %d", ret);
338         return ret;
339     }
340     return NO_ERROR;
341 }
342 
createDtmBlobFromIDpp(const IDisplayColorGS101::IDpp & dpp,uint32_t & blobId)343 int32_t ExynosDisplayDrmInterfaceModule::createDtmBlobFromIDpp(
344         const IDisplayColorGS101::IDpp &dpp, uint32_t &blobId)
345 {
346     struct hdr_tm_data tm_data;
347 
348     if (dpp.Dtm().config == nullptr) {
349         ALOGE("no dpp DTM config");
350         return -EINVAL;
351     }
352 
353     if ((dpp.Dtm().config->tf_data.posx.size() != DRM_SAMSUNG_HDR_TM_LUT_LEN) ||
354         (dpp.Dtm().config->tf_data.posy.size() != DRM_SAMSUNG_HDR_TM_LUT_LEN)) {
355         HWC_LOGE(mExynosDisplay, "%s: dtm pos size (%zu, %zu)",
356                 __func__, dpp.Dtm().config->tf_data.posx.size(),
357                 dpp.Dtm().config->tf_data.posy.size());
358         return -EINVAL;
359     }
360 
361     for (uint32_t i = 0; i < DRM_SAMSUNG_HDR_TM_LUT_LEN; i++) {
362         tm_data.posx[i] = dpp.Dtm().config->tf_data.posx[i];
363         tm_data.posy[i] = dpp.Dtm().config->tf_data.posy[i];
364     }
365 
366     tm_data.coeff_r = dpp.Dtm().config->coeff_r;
367     tm_data.coeff_g = dpp.Dtm().config->coeff_g;
368     tm_data.coeff_b = dpp.Dtm().config->coeff_b;
369     tm_data.rng_x_min = dpp.Dtm().config->rng_x_min;
370     tm_data.rng_x_max = dpp.Dtm().config->rng_x_max;
371     tm_data.rng_y_min = dpp.Dtm().config->rng_y_min;
372     tm_data.rng_y_max = dpp.Dtm().config->rng_y_max;
373 
374     int ret = mDrmDevice->CreatePropertyBlob(&tm_data, sizeof(tm_data), &blobId);
375     if (ret) {
376         HWC_LOGE(mExynosDisplay, "Failed to create tm_data blob %d", ret);
377         return ret;
378     }
379 
380     return NO_ERROR;
381 }
createOetfBlobFromIDpp(const IDisplayColorGS101::IDpp & dpp,uint32_t & blobId)382 int32_t ExynosDisplayDrmInterfaceModule::createOetfBlobFromIDpp(
383         const IDisplayColorGS101::IDpp &dpp, uint32_t &blobId)
384 {
385     struct hdr_oetf_lut oetf_lut;
386 
387     if (dpp.OetfLut().config == nullptr) {
388         ALOGE("no dpp OETF config");
389         return -EINVAL;
390     }
391 
392     if ((dpp.OetfLut().config->tf_data.posx.size() != DRM_SAMSUNG_HDR_OETF_LUT_LEN) ||
393         (dpp.OetfLut().config->tf_data.posy.size() != DRM_SAMSUNG_HDR_OETF_LUT_LEN)) {
394         HWC_LOGE(mExynosDisplay, "%s: oetf pos size (%zu, %zu)",
395                 __func__, dpp.OetfLut().config->tf_data.posx.size(),
396                 dpp.OetfLut().config->tf_data.posy.size());
397         return -EINVAL;
398     }
399 
400     for (uint32_t i = 0; i < DRM_SAMSUNG_HDR_OETF_LUT_LEN; i++) {
401         oetf_lut.posx[i] = dpp.OetfLut().config->tf_data.posx[i];
402         oetf_lut.posy[i] = dpp.OetfLut().config->tf_data.posy[i];
403     }
404     int ret = mDrmDevice->CreatePropertyBlob(&oetf_lut, sizeof(oetf_lut), &blobId);
405     if (ret) {
406         HWC_LOGE(mExynosDisplay, "Failed to create oetf lut blob %d", ret);
407         return ret;
408     }
409     return NO_ERROR;
410 }
411 
412 template<typename StageDataType>
setDisplayColorBlob(const DrmProperty & prop,const uint32_t type,const StageDataType & stage,const IDisplayColorGS101::IDqe & dqe,ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)413 int32_t ExynosDisplayDrmInterfaceModule::setDisplayColorBlob(
414         const DrmProperty &prop,
415         const uint32_t type,
416         const StageDataType &stage,
417         const IDisplayColorGS101::IDqe &dqe,
418         ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq)
419 {
420     /* dirty bit is valid only if enable is true */
421     if (!prop.id())
422         return NO_ERROR;
423     if (!mForceDisplayColorSetting && stage.enable && !stage.dirty)
424         return NO_ERROR;
425 
426     int32_t ret = 0;
427     uint32_t blobId = 0;
428 
429     if (stage.enable) {
430         switch (type) {
431             case DqeBlobs::CGC:
432                 ret = createCgcBlobFromIDqe(dqe, blobId);
433                 break;
434             case DqeBlobs::DEGAMMA_LUT:
435                 ret = createDegammaLutBlobFromIDqe(dqe, blobId);
436                 break;
437             case DqeBlobs::REGAMMA_LUT:
438                 ret = createRegammaLutBlobFromIDqe(dqe, blobId);
439                 break;
440             case DqeBlobs::GAMMA_MAT:
441                 ret = createGammaMatBlobFromIDqe(dqe, blobId);
442                 break;
443             case DqeBlobs::LINEAR_MAT:
444                 ret = createLinearMatBlobFromIDqe(dqe, blobId);
445                 break;
446             case DqeBlobs::DISP_DITHER:
447                 ret = createDispDitherBlobFromIDqe(dqe, blobId);
448                 break;
449             case DqeBlobs::CGC_DITHER:
450                 ret = createCgcDitherBlobFromIDqe(dqe, blobId);
451                 break;
452             default:
453                 ret = -EINVAL;
454         }
455         if (ret != NO_ERROR) {
456             HWC_LOGE(mExynosDisplay, "%s: create blob fail", __func__);
457             return ret;
458         }
459     }
460 
461     /* Skip setting when previous and current setting is same with 0 */
462     if ((blobId == 0) && (mOldDqeBlobs.getBlob(type) == 0))
463         return ret;
464 
465     if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, blobId)) < 0) {
466         HWC_LOGE(mExynosDisplay, "%s: Fail to set property",
467                 __func__);
468         return ret;
469     }
470     mOldDqeBlobs.addBlob(type, blobId);
471 
472     // disp_dither and cgc dither are part of DqeCtrl stage and the notification
473     // will be sent after all data in DqeCtrl stage are applied.
474     if (type != DqeBlobs::DISP_DITHER && type != DqeBlobs::CGC_DITHER)
475         stage.NotifyDataApplied();
476 
477     return ret;
478 }
setDisplayColorSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)479 int32_t ExynosDisplayDrmInterfaceModule::setDisplayColorSetting(
480         ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq)
481 {
482     if (isPrimary() == false)
483         return NO_ERROR;
484     if (!mForceDisplayColorSetting && !mColorSettingChanged)
485         return NO_ERROR;
486 
487     ExynosPrimaryDisplayModule* display =
488         (ExynosPrimaryDisplayModule*)mExynosDisplay;
489 
490     int ret = NO_ERROR;
491     const IDisplayColorGS101::IDqe &dqe = display->getDqe();
492 
493     if ((mDrmCrtc->cgc_lut_property().id() != 0) &&
494         (ret = setDisplayColorBlob(mDrmCrtc->cgc_lut_property(),
495                 static_cast<uint32_t>(DqeBlobs::CGC),
496                 dqe.Cgc(), dqe, drmReq) != NO_ERROR)) {
497         HWC_LOGE(mExynosDisplay, "%s: set Cgc blob fail", __func__);
498         return ret;
499     }
500     if ((ret = setDisplayColorBlob(mDrmCrtc->degamma_lut_property(),
501                 static_cast<uint32_t>(DqeBlobs::DEGAMMA_LUT),
502                 dqe.DegammaLut(), dqe, drmReq) != NO_ERROR)) {
503         HWC_LOGE(mExynosDisplay, "%s: set DegammaLut blob fail", __func__);
504         return ret;
505     }
506     if ((ret = setDisplayColorBlob(mDrmCrtc->gamma_lut_property(),
507                 static_cast<uint32_t>(DqeBlobs::REGAMMA_LUT),
508                 dqe.RegammaLut(), dqe, drmReq) != NO_ERROR)) {
509         HWC_LOGE(mExynosDisplay, "%s: set RegammaLut blob fail", __func__);
510         return ret;
511     }
512     if ((ret = setDisplayColorBlob(mDrmCrtc->gamma_matrix_property(),
513                 static_cast<uint32_t>(DqeBlobs::GAMMA_MAT),
514                 dqe.GammaMatrix(), dqe, drmReq) != NO_ERROR)) {
515         HWC_LOGE(mExynosDisplay, "%s: set GammaMatrix blob fail", __func__);
516         return ret;
517     }
518     if ((ret = setDisplayColorBlob(mDrmCrtc->linear_matrix_property(),
519                 static_cast<uint32_t>(DqeBlobs::LINEAR_MAT),
520                 dqe.LinearMatrix(), dqe, drmReq) != NO_ERROR)) {
521         HWC_LOGE(mExynosDisplay, "%s: set LinearMatrix blob fail", __func__);
522         return ret;
523     }
524     if ((ret = setDisplayColorBlob(mDrmCrtc->disp_dither_property(),
525                 static_cast<uint32_t>(DqeBlobs::DISP_DITHER),
526                 dqe.DqeControl(), dqe, drmReq) != NO_ERROR)) {
527         HWC_LOGE(mExynosDisplay, "%s: set DispDither blob fail", __func__);
528         return ret;
529     }
530     if ((ret = setDisplayColorBlob(mDrmCrtc->cgc_dither_property(),
531                 static_cast<uint32_t>(DqeBlobs::CGC_DITHER),
532                 dqe.DqeControl(), dqe, drmReq) != NO_ERROR)) {
533         HWC_LOGE(mExynosDisplay, "%s: set CgcDither blob fail", __func__);
534         return ret;
535     }
536 
537     const DrmProperty &prop_force_bpc = mDrmCrtc->force_bpc_property();
538     if (prop_force_bpc.id()) {
539         uint32_t bpc = static_cast<uint32_t>(BPC_UNSPECIFIED);
540         if (dqe.DqeControl().enable) {
541             if (dqe.DqeControl().config->force_10bpc)
542                 bpc = static_cast<uint32_t>(BPC_10);
543         }
544         auto [bpcEnum, ret] = DrmEnumParser::halToDrmEnum(bpc, mBpcEnums);
545         if (ret < 0) {
546             HWC_LOGE(mExynosDisplay, "Fail to convert bpc(%d)", bpc);
547         } else {
548             if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop_force_bpc,
549                             bpcEnum, true)) < 0) {
550                 HWC_LOGE(mExynosDisplay, "%s: Fail to set force bpc property",
551                         __func__);
552             }
553         }
554     }
555     dqe.DqeControl().NotifyDataApplied();
556 
557     return NO_ERROR;
558 }
559 
560 template<typename StageDataType>
setPlaneColorBlob(const std::unique_ptr<DrmPlane> & plane,const DrmProperty & prop,const uint32_t type,const StageDataType & stage,const IDisplayColorGS101::IDpp & dpp,const uint32_t dppIndex,ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,bool forceUpdate)561 int32_t ExynosDisplayDrmInterfaceModule::setPlaneColorBlob(
562         const std::unique_ptr<DrmPlane> &plane,
563         const DrmProperty &prop,
564         const uint32_t type,
565         const StageDataType &stage,
566         const IDisplayColorGS101::IDpp &dpp,
567         const uint32_t dppIndex,
568         ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
569         bool forceUpdate)
570 {
571     /* dirty bit is valid only if enable is true */
572     if (!prop.id() || (stage.enable && !stage.dirty && !forceUpdate))
573         return NO_ERROR;
574 
575     uint32_t ix = 0;
576     for (;ix < mOldDppBlobs.size(); ix++) {
577         if (mOldDppBlobs[ix].planeId == plane->id()) {
578             break;
579         }
580     }
581     if (ix >= mOldDppBlobs.size()) {
582         HWC_LOGE(mExynosDisplay, "%s: could not find plane %d", __func__, plane->id());
583         return -EINVAL;
584     }
585     DppBlobs &oldDppBlobs = mOldDppBlobs[ix];
586 
587     int32_t ret = 0;
588     uint32_t blobId = 0;
589 
590     if (stage.enable) {
591         switch (type) {
592             case DppBlobs::EOTF:
593                 ret = createEotfBlobFromIDpp(dpp, blobId);
594                 break;
595             case DppBlobs::GM:
596                 ret = createGmBlobFromIDpp(dpp, blobId);
597                 break;
598             case DppBlobs::DTM:
599                 ret = createDtmBlobFromIDpp(dpp, blobId);
600                 break;
601             case DppBlobs::OETF:
602                 ret = createOetfBlobFromIDpp(dpp, blobId);
603                 break;
604             default:
605                 ret = -EINVAL;
606         }
607         if (ret != NO_ERROR) {
608             HWC_LOGE(mExynosDisplay, "%s: create blob fail", __func__);
609             return ret;
610         }
611     }
612 
613     /* Skip setting when previous and current setting is same with 0 */
614     if ((blobId == 0) && (oldDppBlobs.getBlob(type) == 0) && !forceUpdate)
615         return ret;
616 
617     if ((ret = drmReq.atomicAddProperty(plane->id(), prop, blobId)) < 0) {
618         HWC_LOGE(mExynosDisplay, "%s: Fail to set property",
619                 __func__);
620         return ret;
621     }
622 
623     oldDppBlobs.addBlob(type, blobId);
624     stage.NotifyDataApplied();
625 
626     return ret;
627 }
628 
setPlaneColorSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,const std::unique_ptr<DrmPlane> & plane,const exynos_win_config_data & config,uint32_t & solidColor)629 int32_t ExynosDisplayDrmInterfaceModule::setPlaneColorSetting(
630         ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
631         const std::unique_ptr<DrmPlane> &plane,
632         const exynos_win_config_data &config, uint32_t &solidColor)
633 {
634     if ((mColorSettingChanged == false) ||
635         (isPrimary() == false))
636         return NO_ERROR;
637 
638     if ((config.assignedMPP == nullptr) ||
639         (config.assignedMPP->mAssignedSources.size() == 0)) {
640         HWC_LOGE(mExynosDisplay, "%s:: config's mpp source size is invalid",
641                 __func__);
642         return -EINVAL;
643     }
644     ExynosMPPSource* mppSource = config.assignedMPP->mAssignedSources[0];
645     if (mppSource->mSourceType >= MPP_SOURCE_MAX) {
646         HWC_LOGE(mExynosDisplay,
647                 "%s: invalid mpp source type (%d)", __func__, mppSource->mSourceType);
648         return -EINVAL;
649     }
650 
651     ExynosPrimaryDisplayModule* display = (ExynosPrimaryDisplayModule*)mExynosDisplay;
652 
653     /*
654      * Color conversion of Client and Exynos composition buffer
655      * is already addressed by GLES or G2D. But as of now, 'dim SDR' is only
656      * supported by HWC/displaycolor, we need put client composition under
657      * control of HWC/displaycolor.
658      */
659     if (!display->hasDppForLayer(mppSource)) {
660         if (mppSource->mSourceType == MPP_SOURCE_LAYER) {
661             HWC_LOGE(mExynosDisplay,
662                 "%s: layer need color conversion but there is no IDpp",
663                 __func__);
664             return -EINVAL;
665         } else if (mppSource->mSourceType == MPP_SOURCE_COMPOSITION_TARGET) {
666             return NO_ERROR;
667         } else {
668             HWC_LOGE(mExynosDisplay,
669                 "%s: invalid mpp source type (%d)", __func__, mppSource->mSourceType);
670             return -EINVAL;
671         }
672     }
673 
674     if (mppSource->mSourceType == MPP_SOURCE_LAYER) {
675         ExynosLayer* layer = (ExynosLayer*)mppSource;
676 
677         /* color conversion was already handled by m2mMPP */
678         if ((layer->mM2mMPP != nullptr) &&
679             (layer->mSrcImg.dataSpace != layer->mMidImg.dataSpace)) {
680             return NO_ERROR;
681         }
682     }
683 
684     const IDisplayColorGS101::IDpp &dpp = display->getDppForLayer(mppSource);
685     const uint32_t dppIndex = static_cast<uint32_t>(display->getDppIndexForLayer(mppSource));
686     bool planeChanged = display->checkAndSaveLayerPlaneId(mppSource, plane->id());
687 
688     auto &color = dpp.SolidColor();
689     // exynos_win_config_data.color ARGB
690     solidColor = (color.a << 24) | (color.r << 16) | (color.g << 8) | color.b;
691 
692     int ret = 0;
693     if ((ret = setPlaneColorBlob(plane, plane->eotf_lut_property(),
694                 static_cast<uint32_t>(DppBlobs::EOTF),
695                 dpp.EotfLut(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
696         HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set oetf blob fail",
697                 __func__, dppIndex);
698         return ret;
699     }
700     if ((ret = setPlaneColorBlob(plane, plane->gammut_matrix_property(),
701                 static_cast<uint32_t>(DppBlobs::GM),
702                 dpp.Gm(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
703         HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set GM blob fail",
704                 __func__, dppIndex);
705         return ret;
706     }
707     if ((ret = setPlaneColorBlob(plane, plane->tone_mapping_property(),
708                 static_cast<uint32_t>(DppBlobs::DTM),
709                 dpp.Dtm(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
710         HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set DTM blob fail",
711                 __func__, dppIndex);
712         return ret;
713     }
714     if ((ret = setPlaneColorBlob(plane, plane->oetf_lut_property(),
715                 static_cast<uint32_t>(DppBlobs::OETF),
716                 dpp.OetfLut(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
717         HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set OETF blob fail",
718                 __func__, dppIndex);
719         return ret;
720     }
721 
722     return 0;
723 }
724 
~SaveBlob()725 ExynosDisplayDrmInterfaceModule::SaveBlob::~SaveBlob()
726 {
727     for (auto &it: blobs) {
728         mDrmDevice->DestroyPropertyBlob(it);
729     }
730     blobs.clear();
731 }
732 
addBlob(uint32_t type,uint32_t blob)733 void ExynosDisplayDrmInterfaceModule::SaveBlob::addBlob(
734         uint32_t type, uint32_t blob)
735 {
736     if (type >= blobs.size()) {
737         ALOGE("Invalid dqe blop type: %d", type);
738         return;
739     }
740     if (blobs[type] > 0)
741         mDrmDevice->DestroyPropertyBlob(blobs[type]);
742 
743     blobs[type] = blob;
744 }
745 
getBlob(uint32_t type)746 uint32_t ExynosDisplayDrmInterfaceModule::SaveBlob::getBlob(uint32_t type)
747 {
748     if (type >= blobs.size()) {
749         ALOGE("Invalid dqe blop type: %d", type);
750         return 0;
751     }
752     return blobs[type];
753 }
754 
getDisplayInfo(std::vector<displaycolor::DisplayInfo> & display_info)755 void ExynosDisplayDrmInterfaceModule::getDisplayInfo(
756         std::vector<displaycolor::DisplayInfo> &display_info) {
757     displaycolor::DisplayInfo primary_display;
758     auto &tb = primary_display.brightness_table;
759     auto *brightnessTable = mExynosDisplay->mBrightnessController->getBrightnessTable();
760 
761     tb.nbm_nits_min = brightnessTable[toUnderlying(BrightnessRange::NORMAL)].mNitsStart;
762     tb.nbm_nits_max = brightnessTable[toUnderlying(BrightnessRange::NORMAL)].mNitsEnd;
763     tb.nbm_dbv_min = brightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBklStart;
764     tb.nbm_dbv_max = brightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBklEnd;
765 
766     tb.hbm_nits_min = brightnessTable[toUnderlying(BrightnessRange::HBM)].mNitsStart;
767     tb.hbm_nits_max = brightnessTable[toUnderlying(BrightnessRange::HBM)].mNitsEnd;
768     tb.hbm_dbv_min = brightnessTable[toUnderlying(BrightnessRange::HBM)].mBklStart;
769     tb.hbm_dbv_max = brightnessTable[toUnderlying(BrightnessRange::HBM)].mBklEnd;
770 
771     primary_display.panel_name = GetPanelName();
772     primary_display.panel_serial = GetPanelSerial();
773 
774     display_info.push_back(primary_display);
775 }
776 
GetPanelInfo(const std::string & sysfs_rel,char delim)777 const std::string ExynosDisplayDrmInterfaceModule::GetPanelInfo(const std::string &sysfs_rel,
778                                                                 char delim) {
779     ExynosPrimaryDisplayModule* display = (ExynosPrimaryDisplayModule*)mExynosDisplay;
780     const DisplayType type = display->getBuiltInDisplayType();
781     const std::string &sysfs = display->getPanelSysfsPath(type);
782 
783     if (sysfs.empty()) {
784         return "";
785     }
786 
787     std::string info;
788     if (readLineFromFile(sysfs + "/" + sysfs_rel, info, delim) != OK) {
789         ALOGE("failed reading %s/%s", sysfs.c_str(), sysfs_rel.c_str());
790         return "";
791     }
792 
793     return info;
794 }
795 
796 /* For Histogram */
createHistoRoiBlob(uint32_t & blobId)797 int32_t ExynosDisplayDrmInterfaceModule::createHistoRoiBlob(uint32_t &blobId) {
798     struct histogram_roi histo_roi;
799 
800     std::unique_lock<std::mutex> lk((mHistogramInfo->mSetHistInfoMutex));
801     histo_roi.start_x = mHistogramInfo->getHistogramROI().start_x;
802     histo_roi.start_y = mHistogramInfo->getHistogramROI().start_y;
803     histo_roi.hsize = mHistogramInfo->getHistogramROI().hsize;
804     histo_roi.vsize = mHistogramInfo->getHistogramROI().vsize;
805 
806     int ret = mDrmDevice->CreatePropertyBlob(&histo_roi, sizeof(histo_roi), &blobId);
807     if (ret) {
808         HWC_LOGE(mExynosDisplay, "Failed to create histogram roi blob %d", ret);
809         return ret;
810     }
811 
812     return NO_ERROR;
813 }
814 
createHistoWeightsBlob(uint32_t & blobId)815 int32_t ExynosDisplayDrmInterfaceModule::createHistoWeightsBlob(uint32_t &blobId) {
816     struct histogram_weights histo_weights;
817 
818     std::unique_lock<std::mutex> lk((mHistogramInfo->mSetHistInfoMutex));
819     histo_weights.weight_r = mHistogramInfo->getHistogramWeights().weight_r;
820     histo_weights.weight_g = mHistogramInfo->getHistogramWeights().weight_g;
821     histo_weights.weight_b = mHistogramInfo->getHistogramWeights().weight_b;
822 
823     int ret = mDrmDevice->CreatePropertyBlob(&histo_weights, sizeof(histo_weights), &blobId);
824     if (ret) {
825         HWC_LOGE(mExynosDisplay, "Failed to create histogram weights blob %d", ret);
826         return ret;
827     }
828 
829     return NO_ERROR;
830 }
831 
setDisplayHistoBlob(const DrmProperty & prop,const uint32_t type,ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)832 int32_t ExynosDisplayDrmInterfaceModule::setDisplayHistoBlob(
833         const DrmProperty &prop, const uint32_t type,
834         ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) {
835     if (!prop.id()) return NO_ERROR;
836 
837     int32_t ret = NO_ERROR;
838     uint32_t blobId = 0;
839 
840     switch (type) {
841         case HistoBlobs::ROI:
842             ret = createHistoRoiBlob(blobId);
843             break;
844         case HistoBlobs::WEIGHTS:
845             ret = createHistoWeightsBlob(blobId);
846             break;
847         default:
848             ret = -EINVAL;
849     }
850     if (ret != NO_ERROR) {
851         HWC_LOGE(mExynosDisplay, "%s: Failed to create blob", __func__);
852         return ret;
853     }
854 
855     /* Skip setting when previous and current setting is same with 0 */
856     if ((blobId == 0) && (mOldHistoBlobs.getBlob(type) == 0)) return ret;
857 
858     if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, blobId)) < 0) {
859         HWC_LOGE(mExynosDisplay, "%s: Failed to add property", __func__);
860         return ret;
861     }
862     mOldHistoBlobs.addBlob(type, blobId);
863 
864     return ret;
865 }
866 
setDisplayHistogramSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)867 int32_t ExynosDisplayDrmInterfaceModule::setDisplayHistogramSetting(
868         ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) {
869     if ((isHistogramInfoRegistered() == false) || (isPrimary() == false)) return NO_ERROR;
870 
871     int ret = NO_ERROR;
872 
873     if ((ret = setDisplayHistoBlob(mDrmCrtc->histogram_roi_property(),
874                                    static_cast<uint32_t>(HistoBlobs::ROI), drmReq) != NO_ERROR)) {
875         HWC_LOGE(mExynosDisplay, "%s: Failed to set Histo_ROI blob", __func__);
876         return ret;
877     }
878     if ((ret = setDisplayHistoBlob(mDrmCrtc->histogram_weights_property(),
879                                    static_cast<uint32_t>(HistoBlobs::WEIGHTS),
880                                    drmReq) != NO_ERROR)) {
881         HWC_LOGE(mExynosDisplay, "%s: Failed to set Histo_Weights blob", __func__);
882         return ret;
883     }
884 
885     const DrmProperty &prop_histo_threshold = mDrmCrtc->histogram_threshold_property();
886     if (prop_histo_threshold.id()) {
887         if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop_histo_threshold,
888                                             (uint64_t)(mHistogramInfo->getHistogramThreshold()),
889                                             true)) < 0) {
890             HWC_LOGE(mExynosDisplay, "%s: Failed to set histogram thereshold property", __func__);
891             return ret;
892         }
893     }
894 
895     return NO_ERROR;
896 }
897 
setHistogramControl(hidl_histogram_control_t control)898 int32_t ExynosDisplayDrmInterfaceModule::setHistogramControl(hidl_histogram_control_t control) {
899     if ((isHistogramInfoRegistered() == false) || (isPrimary() == false)) return NO_ERROR;
900 
901     int ret = NO_ERROR;
902     uint32_t crtc_id = mDrmCrtc->id();
903 
904     if (control == hidl_histogram_control_t::HISTOGRAM_CONTROL_REQUEST) {
905         ret = mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_HISTOGRAM_REQUEST, (void *)&crtc_id);
906     } else if (control == hidl_histogram_control_t::HISTOGRAM_CONTROL_CANCEL) {
907         ret = mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_HISTOGRAM_CANCEL, (void *)&crtc_id);
908     }
909 
910     return ret;
911 }
912 
setHistogramData(void * bin)913 int32_t ExynosDisplayDrmInterfaceModule::setHistogramData(void *bin) {
914     if (!bin) return -EINVAL;
915 
916     /*
917      * There are two handling methods.
918      * For ContentSampling in HWC_2.3 API, histogram bin needs to be accumulated.
919      * For Histogram IDL, histogram bin need to be sent to IDL block.
920      */
921     if (mHistogramInfo->getHistogramType() == HistogramInfo::HistogramType::HISTOGRAM_HIDL) {
922         (mHistogramInfo.get())->callbackHistogram((char16_t *)bin);
923     } else {
924         /*
925          * ContentSampling in HWC2.3 API is not supported
926          */
927         return -ENOTSUP;
928     }
929 
930     return NO_ERROR;
931 }
932 
933 //////////////////////////////////////////////////// ExynosPrimaryDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosPrimaryDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)934 ExynosPrimaryDisplayDrmInterfaceModule::ExynosPrimaryDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
935 : ExynosDisplayDrmInterfaceModule(exynosDisplay)
936 {
937 }
938 
~ExynosPrimaryDisplayDrmInterfaceModule()939 ExynosPrimaryDisplayDrmInterfaceModule::~ExynosPrimaryDisplayDrmInterfaceModule()
940 {
941 }
942 
943 //////////////////////////////////////////////////// ExynosExternalDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosExternalDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)944 ExynosExternalDisplayDrmInterfaceModule::ExynosExternalDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
945 : ExynosDisplayDrmInterfaceModule(exynosDisplay)
946 {
947 }
948 
~ExynosExternalDisplayDrmInterfaceModule()949 ExynosExternalDisplayDrmInterfaceModule::~ExynosExternalDisplayDrmInterfaceModule()
950 {
951 }
952