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