1 /*
2  * Copyright (C) 2022 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 <drm/samsung_drm.h>
18 #include "DisplayColorModule.h"
19 
20 using namespace android;
21 namespace gs {
22 
23 template <typename T, typename M>
convertDqeMatrixDataToDrmMatrix(T & colorMatrix,M & mat,uint32_t dimension)24 int32_t convertDqeMatrixDataToDrmMatrix(T &colorMatrix, M &mat, uint32_t dimension) {
25     if (colorMatrix.coeffs.size() != (dimension * dimension)) {
26         ALOGE("Invalid coeff size(%zu)",
27                 colorMatrix.coeffs.size());
28         return -EINVAL;
29     }
30     if (colorMatrix.offsets.size() != dimension) {
31         ALOGE("Invalid offset size(%zu)",
32                 colorMatrix.offsets.size());
33         return -EINVAL;
34     }
35     for (uint32_t i = 0; i < (dimension * dimension); i++) {
36         mat.coeffs[i] = colorMatrix.coeffs[i];
37     }
38 
39     for (uint32_t i = 0; i < dimension; i++) {
40         mat.offsets[i] = colorMatrix.offsets[i];
41     }
42     return NO_ERROR;
43 }
44 
eotf(const GsInterfaceType::IDpp::EotfData::ConfigType * config,DrmDevice * drm,uint32_t & blobId)45 int32_t ColorDrmBlobFactory::eotf(const GsInterfaceType::IDpp::EotfData::ConfigType *config,
46                                   DrmDevice *drm, uint32_t &blobId) {
47     struct hdr_eotf_lut eotfLut;
48 
49     if (config == nullptr) {
50         ALOGE("no dpp eotf config");
51         return -EINVAL;
52     }
53 
54     if ((config->tf_data.posx.size() != DRM_SAMSUNG_HDR_EOTF_LUT_LEN) ||
55         (config->tf_data.posy.size() != DRM_SAMSUNG_HDR_EOTF_LUT_LEN)) {
56         ALOGE("%s: eotf pos size (%zu, %zu)", __func__, config->tf_data.posx.size(),
57               config->tf_data.posy.size());
58         return -EINVAL;
59     }
60 
61     for (uint32_t i = 0; i < DRM_SAMSUNG_HDR_EOTF_LUT_LEN; i++) {
62         eotfLut.posx[i] = config->tf_data.posx[i];
63         eotfLut.posy[i] = config->tf_data.posy[i];
64     }
65     int ret = drm->CreatePropertyBlob(&eotfLut, sizeof(eotfLut), &blobId);
66     if (ret) {
67         ALOGE("Failed to create eotf lut blob %d", ret);
68         return ret;
69     }
70     return NO_ERROR;
71 }
72 
gm(const GsInterfaceType::IDpp::GmData::ConfigType * config,DrmDevice * drm,uint32_t & blobId)73 int32_t ColorDrmBlobFactory::gm(const GsInterfaceType::IDpp::GmData::ConfigType *config,
74                                 DrmDevice *drm, uint32_t &blobId) {
75     int ret = 0;
76     struct hdr_gm_data gmMatrix;
77 
78     if (config == nullptr) {
79         ALOGE("no dpp GM config");
80         return -EINVAL;
81     }
82 
83     if ((ret = convertDqeMatrixDataToDrmMatrix(config->matrix_data, gmMatrix,
84                                             DRM_SAMSUNG_HDR_GM_DIMENS)) != NO_ERROR) {
85         ALOGE("Failed to convert gm matrix");
86         return ret;
87     }
88     ret = drm->CreatePropertyBlob(&gmMatrix, sizeof(gmMatrix), &blobId);
89     if (ret) {
90         ALOGE("Failed to create gm matrix blob %d", ret);
91         return ret;
92     }
93     return NO_ERROR;
94 }
95 
dtm(const GsInterfaceType::IDpp::DtmData::ConfigType * config,DrmDevice * drm,uint32_t & blobId)96 int32_t ColorDrmBlobFactory::dtm(const GsInterfaceType::IDpp::DtmData::ConfigType *config,
97                                  DrmDevice *drm, uint32_t &blobId) {
98     struct hdr_tm_data tmData;
99 
100     if (config == nullptr) {
101         ALOGE("no dpp DTM config");
102         return -EINVAL;
103     }
104 
105     if ((config->tf_data.posx.size() != DRM_SAMSUNG_HDR_TM_LUT_LEN) ||
106         (config->tf_data.posy.size() != DRM_SAMSUNG_HDR_TM_LUT_LEN)) {
107         ALOGE("%s: dtm pos size (%zu, %zu)", __func__, config->tf_data.posx.size(),
108               config->tf_data.posy.size());
109         return -EINVAL;
110     }
111 
112     for (uint32_t i = 0; i < DRM_SAMSUNG_HDR_TM_LUT_LEN; i++) {
113         tmData.posx[i] = config->tf_data.posx[i];
114         tmData.posy[i] = config->tf_data.posy[i];
115     }
116 
117     tmData.coeff_r = config->coeff_r;
118     tmData.coeff_g = config->coeff_g;
119     tmData.coeff_b = config->coeff_b;
120     tmData.rng_x_min = config->rng_x_min;
121     tmData.rng_x_max = config->rng_x_max;
122     tmData.rng_y_min = config->rng_y_min;
123     tmData.rng_y_max = config->rng_y_max;
124 
125     int ret = drm->CreatePropertyBlob(&tmData, sizeof(tmData), &blobId);
126     if (ret) {
127         ALOGE("Failed to create tmData blob %d", ret);
128         return ret;
129     }
130 
131     return NO_ERROR;
132 }
133 
oetf(const GsInterfaceType::IDpp::OetfData::ConfigType * config,DrmDevice * drm,uint32_t & blobId)134 int32_t ColorDrmBlobFactory::oetf(const GsInterfaceType::IDpp::OetfData::ConfigType *config,
135                                   DrmDevice *drm, uint32_t &blobId) {
136     struct hdr_oetf_lut oetfLut;
137 
138     if (config == nullptr) {
139         ALOGE("no dpp OETF config");
140         return -EINVAL;
141     }
142 
143     if ((config->tf_data.posx.size() != DRM_SAMSUNG_HDR_OETF_LUT_LEN) ||
144         (config->tf_data.posy.size() != DRM_SAMSUNG_HDR_OETF_LUT_LEN)) {
145         ALOGE("%s: oetf pos size (%zu, %zu)", __func__, config->tf_data.posx.size(),
146               config->tf_data.posy.size());
147         return -EINVAL;
148     }
149 
150     for (uint32_t i = 0; i < DRM_SAMSUNG_HDR_OETF_LUT_LEN; i++) {
151         oetfLut.posx[i] = config->tf_data.posx[i];
152         oetfLut.posy[i] = config->tf_data.posy[i];
153     }
154     int ret = drm->CreatePropertyBlob(&oetfLut, sizeof(oetfLut), &blobId);
155     if (ret) {
156         ALOGE("Failed to create oetf lut blob %d", ret);
157         return ret;
158     }
159     return NO_ERROR;
160 }
161 
gammaMatrix(const GsInterfaceType::IDqe::DqeMatrixData::ConfigType * config,DrmDevice * drm,uint32_t & blobId)162 int32_t ColorDrmBlobFactory::gammaMatrix(
163         const GsInterfaceType::IDqe::DqeMatrixData::ConfigType *config, DrmDevice *drm,
164         uint32_t &blobId) {
165     int ret = 0;
166     struct exynos_matrix gammaMatrix;
167     if ((ret = convertDqeMatrixDataToDrmMatrix(config->matrix_data, gammaMatrix,
168                                             DRM_SAMSUNG_MATRIX_DIMENS)) != NO_ERROR) {
169         ALOGE("Failed to convert gamma matrix");
170         return ret;
171     }
172     ret = drm->CreatePropertyBlob(&gammaMatrix, sizeof(gammaMatrix), &blobId);
173     if (ret) {
174         ALOGE("Failed to create gamma matrix blob %d", ret);
175         return ret;
176     }
177 
178     return NO_ERROR;
179 }
180 
degamma(const uint64_t drmLutSize,const GsInterfaceType::IDqe::DegammaLutData::ConfigType * config,DrmDevice * drm,uint32_t & blobId)181 int32_t ColorDrmBlobFactory::degamma(const uint64_t drmLutSize,
182         const GsInterfaceType::IDqe::DegammaLutData::ConfigType *config, DrmDevice *drm,
183         uint32_t &blobId) {
184     if (config == nullptr) {
185         ALOGE("no degamma config");
186         return -EINVAL;
187     }
188     using ConfigType = typename GsInterfaceType::IDqe::DegammaLutData::ConfigType;
189     if (drmLutSize != ConfigType::kLutLen) {
190         ALOGE("degamma lut size mismatch");
191         return -EINVAL;
192     }
193 
194     struct drm_color_lut colorLut[ConfigType::kLutLen];
195     for (uint32_t i = 0; i < ConfigType::kLutLen; i++) {
196         colorLut[i].red = config->values[i];
197     }
198     int ret = drm->CreatePropertyBlob(colorLut, sizeof(colorLut), &blobId);
199     if (ret) {
200         ALOGE("Failed to create degamma lut blob %d", ret);
201         return ret;
202     }
203     return NO_ERROR;
204 }
205 
linearMatrix(const GsInterfaceType::IDqe::DqeMatrixData::ConfigType * config,DrmDevice * drm,uint32_t & blobId)206 int32_t ColorDrmBlobFactory::linearMatrix(
207         const GsInterfaceType::IDqe::DqeMatrixData::ConfigType *config, DrmDevice *drm,
208         uint32_t &blobId) {
209     int ret = 0;
210     struct exynos_matrix linear_matrix;
211     if ((ret = convertDqeMatrixDataToDrmMatrix(config->matrix_data, linear_matrix,
212                                             DRM_SAMSUNG_MATRIX_DIMENS)) != NO_ERROR) {
213         ALOGE("Failed to convert linear matrix");
214         return ret;
215     }
216     ret = drm->CreatePropertyBlob(&linear_matrix, sizeof(linear_matrix), &blobId);
217     if (ret) {
218         ALOGE("Failed to create linear matrix blob %d", ret);
219         return ret;
220     }
221 
222     return NO_ERROR;
223 }
224 
cgc(const GsInterfaceType::IDqe::CgcData::ConfigType * config,DrmDevice * drm,uint32_t & blobId)225 int32_t ColorDrmBlobFactory::cgc(const GsInterfaceType::IDqe::CgcData::ConfigType *config,
226                                  DrmDevice *drm, uint32_t &blobId) {
227     struct cgc_lut cgc;
228     if (config == nullptr) {
229         ALOGE("no CGC config");
230         return -EINVAL;
231     }
232 
233     if ((config->r_values.size() != DRM_SAMSUNG_CGC_LUT_REG_CNT) ||
234         (config->g_values.size() != DRM_SAMSUNG_CGC_LUT_REG_CNT) ||
235         (config->b_values.size() != DRM_SAMSUNG_CGC_LUT_REG_CNT)) {
236         ALOGE("CGC data size is not same (r: %zu, g: %zu: b: %zu)", config->r_values.size(),
237               config->g_values.size(), config->b_values.size());
238         return -EINVAL;
239     }
240 
241     for (uint32_t i = 0; i < DRM_SAMSUNG_CGC_LUT_REG_CNT; i++) {
242         cgc.r_values[i] = config->r_values[i];
243         cgc.g_values[i] = config->g_values[i];
244         cgc.b_values[i] = config->b_values[i];
245     }
246     int ret = drm->CreatePropertyBlob(&cgc, sizeof(cgc_lut), &blobId);
247     if (ret) {
248         ALOGE("Failed to create cgc blob %d", ret);
249         return ret;
250     }
251     return NO_ERROR;
252 }
253 
cgcDither(const GsInterfaceType::IDqe::DqeControlData::ConfigType * config,DrmDevice * drm,uint32_t & blobId)254 int32_t ColorDrmBlobFactory::cgcDither(
255         const GsInterfaceType::IDqe::DqeControlData::ConfigType *config, DrmDevice *drm,
256         uint32_t &blobId) {
257     int ret = 0;
258     if (config->cgc_dither_override == false) {
259         blobId = 0;
260         return ret;
261     }
262 
263     ret = drm->CreatePropertyBlob((void *)&config->cgc_dither_reg, sizeof(config->cgc_dither_reg),
264                                   &blobId);
265     if (ret) {
266         ALOGE("Failed to create disp dither blob %d", ret);
267         return ret;
268     }
269     return NO_ERROR;
270 }
271 
regamma(const uint64_t drmLutSize,const GsInterfaceType::IDqe::RegammaLutData::ConfigType * config,DrmDevice * drm,uint32_t & blobId)272 int32_t ColorDrmBlobFactory::regamma(
273         const uint64_t drmLutSize,
274         const GsInterfaceType::IDqe::RegammaLutData::ConfigType *config, DrmDevice *drm,
275         uint32_t &blobId) {
276     if (config == nullptr) {
277         ALOGE("no regamma config");
278         return -EINVAL;
279     }
280 
281     using ConfigType = typename GsInterfaceType::IDqe::RegammaLutData::ConfigType;
282     if (drmLutSize != ConfigType::kChannelLutLen) {
283         ALOGE("gamma lut size mismatch");
284         return -EINVAL;
285     }
286 
287     struct drm_color_lut colorLut[ConfigType::kChannelLutLen];
288     for (uint32_t i = 0; i < ConfigType::kChannelLutLen; i++) {
289         colorLut[i].red = config->r_values[i];
290         colorLut[i].green = config->g_values[i];
291         colorLut[i].blue = config->b_values[i];
292     }
293     int ret = drm->CreatePropertyBlob(colorLut, sizeof(colorLut), &blobId);
294     if (ret) {
295         ALOGE("Failed to create gamma lut blob %d", ret);
296         return ret;
297     }
298     return NO_ERROR;
299 }
300 
displayDither(const GsInterfaceType::IDqe::DqeControlData::ConfigType * config,DrmDevice * drm,uint32_t & blobId)301 int32_t ColorDrmBlobFactory::displayDither(
302         const GsInterfaceType::IDqe::DqeControlData::ConfigType *config, DrmDevice *drm,
303         uint32_t &blobId) {
304     int ret = 0;
305     if (config->disp_dither_override == false) {
306         blobId = 0;
307         return ret;
308     }
309 
310     ret = drm->CreatePropertyBlob((void *)&config->disp_dither_reg, sizeof(config->disp_dither_reg),
311                                   &blobId);
312     if (ret) {
313         ALOGE("Failed to create disp dither blob %d", ret);
314         return ret;
315     }
316 
317     return NO_ERROR;
318 }
319 
320 } // namespace gs
321