1 /*
2 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <drm.h>
33 // The 3 headers above are a workaround to prevent kernel drm.h from being used that has the
34 // "virtual" keyword used for a variable. In future replace libdrm version drm.h with kernel
35 // version drm/drm.h
36 #include <drm_logger.h>
37 #include <drm/drm_fourcc.h>
38 #include <drm/sde_drm.h>
39
40 #include <cstring>
41 #include <sstream>
42 #include <string>
43 #include <tuple>
44 #include <utility>
45 #include <vector>
46 #include <algorithm>
47
48 #include "drm_utils.h"
49 #include "drm_plane.h"
50 #include "drm_property.h"
51
52 namespace sde_drm {
53
54 using std::string;
55 using std::pair;
56 using std::vector;
57 using std::unique_ptr;
58 using std::tuple;
59 using std::stringstream;
60 using std::mutex;
61 using std::lock_guard;
62
63 #define MAX_SCALER_LINEWIDTH 2560
64
65 static struct sde_drm_csc_v1 csc_10bit_convert[kCscTypeMax] = {
66 [kCscYuv2Rgb601L] = {
67 {
68 0x12A000000, 0x000000000, 0x198800000,
69 0x12A000000, 0x7F9B800000, 0x7F30000000,
70 0x12A000000, 0x204800000, 0x000000000,
71 },
72 { 0xffc0, 0xfe00, 0xfe00,},
73 { 0x0, 0x0, 0x0,},
74 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
75 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
76 },
77 [kCscYuv2Rgb601FR] = {
78 {
79 0x100000000, 0x0, 0x167000000,
80 0x100000000, 0x7fa8000000, 0x7f49000000,
81 0x100000000, 0x1c5800000, 0x0,
82 },
83 { 0x0000, 0xfe00, 0xfe00,},
84 { 0x0, 0x0, 0x0,},
85 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
86 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
87 },
88 [kCscYuv2Rgb709L] = {
89 {
90 0x12a000000, 0x0, 0x1cb000000,
91 0x12a000000, 0x7fc9800000, 0x7f77800000,
92 0x12a000000, 0x21d000000, 0x0,
93 },
94 { 0xffc0, 0xfe00, 0xfe00,},
95 { 0x0, 0x0, 0x0,},
96 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
97 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
98 },
99 [kCscYuv2Rgb2020L] = {
100 {
101 0x12b000000, 0x0, 0x1af000000,
102 0x12b000000, 0x7fd0000000, 0x7f59000000,
103 0x12b000000, 0x226000000, 0x0,
104 },
105 { 0xffc0, 0xfe00, 0xfe00,},
106 { 0x0, 0x0, 0x0,},
107 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
108 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
109 },
110 [kCscYuv2Rgb2020FR] = {
111 {
112 0x100000000, 0x0, 0x179800000,
113 0x100000000, 0x7fd6000000, 0x7f6d800000,
114 0x100000000, 0x1e1800000, 0x0,
115 },
116 { 0x0000, 0xfe00, 0xfe00,},
117 { 0x0, 0x0, 0x0,},
118 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
119 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
120 },
121 };
122
123 static uint8_t REFLECT_X = 0;
124 static uint8_t REFLECT_Y = 0;
125 static uint8_t ROTATE_90 = 0;
126 static uint8_t ROTATE_0 = 0;
127
128 // FB Secure Modes
129 static uint8_t NON_SECURE = 0;
130 static uint8_t SECURE = 1;
131 static uint8_t NON_SECURE_DIR_TRANSLATION = 2;
132 static uint8_t SECURE_DIR_TRANSLATION = 3;
133
134 // Multi rect modes
135 static uint8_t MULTIRECT_NONE = 0;
136 static uint8_t MULTIRECT_PARALLEL = 1;
137 static uint8_t MULTIRECT_SERIAL = 2;
138
SetRect(DRMRect & source,drm_clip_rect * target)139 static void SetRect(DRMRect &source, drm_clip_rect *target) {
140 target->x1 = uint16_t(source.left);
141 target->y1 = uint16_t(source.top);
142 target->x2 = uint16_t(source.right);
143 target->y2 = uint16_t(source.bottom);
144 }
145
PopulateReflect(drmModePropertyRes * prop)146 static void PopulateReflect(drmModePropertyRes *prop) {
147 if (REFLECT_X) {
148 return;
149 }
150
151 if (!drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) {
152 return;
153 }
154
155 for (auto i = 0; i < prop->count_enums; i++) {
156 string enum_name(prop->enums[i].name);
157 if (enum_name == "reflect-x") {
158 REFLECT_X = prop->enums[i].value;
159 } else if (enum_name == "reflect-y") {
160 REFLECT_Y = prop->enums[i].value;
161 } else if (enum_name == "rotate-90") {
162 ROTATE_90 = prop->enums[i].value;
163 } else if (enum_name == "rotate-0") {
164 ROTATE_0 = prop->enums[i].value;
165 }
166 }
167 }
168
PopulateSecureModes(drmModePropertyRes * prop)169 static void PopulateSecureModes(drmModePropertyRes *prop) {
170 static bool secure_modes_populated = false;
171 if (!secure_modes_populated) {
172 for (auto i = 0; i < prop->count_enums; i++) {
173 string enum_name(prop->enums[i].name);
174 if (enum_name == "non_sec") {
175 NON_SECURE = prop->enums[i].value;
176 } else if (enum_name == "sec") {
177 SECURE = prop->enums[i].value;
178 } else if (enum_name == "non_sec_direct_translation") {
179 NON_SECURE_DIR_TRANSLATION = prop->enums[i].value;
180 } else if (enum_name == "sec_direct_translation") {
181 SECURE_DIR_TRANSLATION = prop->enums[i].value;
182 }
183 }
184 secure_modes_populated = true;
185 }
186 }
187
PopulateInlineRotationVersion(uint32_t ver)188 static InlineRotationVersion PopulateInlineRotationVersion(uint32_t ver) {
189 switch (ver) {
190 case 0x0000: return InlineRotationVersion::kInlineRotationNone;
191 case 0x0001:
192 case 0x0100: return InlineRotationVersion::kInlineRotationV1;
193 case 0x0200: return InlineRotationVersion::kInlineRotationV2;
194 default: return InlineRotationVersion::kInlineRotationNone;
195 }
196 }
197
PopulateQseedStepVersion(uint32_t hw_ver)198 static QSEEDStepVersion PopulateQseedStepVersion(uint32_t hw_ver) {
199 switch (hw_ver) {
200 case 0x1003: return QSEEDStepVersion::V3;
201 case 0x1004: return QSEEDStepVersion::V4;
202 case 0x2004: return QSEEDStepVersion::V3LITE_V4;
203 case 0x3000: return QSEEDStepVersion::V3LITE_V5;
204 // default value. also corresponds to (hw_ver == 0x1002)
205 default: return QSEEDStepVersion::V2;
206 }
207 }
208
PopulateMultiRectModes(drmModePropertyRes * prop)209 static void PopulateMultiRectModes(drmModePropertyRes *prop) {
210 static bool multirect_modes_populated = false;
211 if (!multirect_modes_populated) {
212 for (auto i = 0; i < prop->count_enums; i++) {
213 string enum_name(prop->enums[i].name);
214 if (enum_name == "none") {
215 MULTIRECT_NONE = prop->enums[i].value;
216 } else if (enum_name == "parallel") {
217 MULTIRECT_PARALLEL = prop->enums[i].value;
218 } else if (enum_name == "serial") {
219 MULTIRECT_SERIAL = prop->enums[i].value;
220 }
221 }
222 multirect_modes_populated = true;
223 }
224 }
225
GetColorLutString(DRMTonemapLutType lut_type)226 static const char *GetColorLutString(DRMTonemapLutType lut_type) {
227 switch (lut_type) {
228 case DRMTonemapLutType::DMA_1D_IGC:
229 return "DMA IGC";
230 case DRMTonemapLutType::DMA_1D_GC:
231 return "DMA GC";
232 case DRMTonemapLutType::VIG_1D_IGC:
233 return "VIG IGC";
234 case DRMTonemapLutType::VIG_3D_GAMUT:
235 return "VIG 3D";
236 default:
237 return "Unknown Lut";
238 }
239 }
240
241 #define __CLASS__ "DRMPlaneManager"
242
GetDRMonemapLutTypeFromPPFeatureID(DRMPPFeatureID id,DRMTonemapLutType * lut_type)243 static bool GetDRMonemapLutTypeFromPPFeatureID(DRMPPFeatureID id, DRMTonemapLutType *lut_type) {
244 switch (id) {
245 case kFeatureDgmIgc:
246 *lut_type = DRMTonemapLutType::DMA_1D_IGC;
247 break;
248 case kFeatureDgmGc:
249 *lut_type = DRMTonemapLutType::DMA_1D_GC;
250 break;
251 case kFeatureVigIgc:
252 *lut_type = DRMTonemapLutType::VIG_1D_IGC;
253 break;
254 case kFeatureVigGamut:
255 *lut_type = DRMTonemapLutType::VIG_3D_GAMUT;
256 break;
257 default:
258 DRM_LOGE("Invalid DRMPPFeature id = %d", id);
259 return false;
260 }
261 return true;
262 }
263
DRMPlaneManager(int fd)264 DRMPlaneManager::DRMPlaneManager(int fd) : fd_(fd) {}
265
Init()266 void DRMPlaneManager::Init() {
267 drmModePlaneRes *resource = drmModeGetPlaneResources(fd_);
268 if (!resource) {
269 return;
270 }
271
272 for (uint32_t i = 0; i < resource->count_planes; i++) {
273 // The enumeration order itself is the priority from high to low
274 unique_ptr<DRMPlane> plane(new DRMPlane(fd_, i));
275 drmModePlane *libdrm_plane = drmModeGetPlane(fd_, resource->planes[i]);
276 if (libdrm_plane) {
277 plane->InitAndParse(libdrm_plane);
278 object_pool_[resource->planes[i]] = std::move(plane);
279 } else {
280 DRM_LOGE("Critical error: drmModeGetPlane() failed for plane %d.", resource->planes[i]);
281 }
282 }
283
284 drmModeFreePlaneResources(resource);
285 }
286
Perform(DRMOps code,uint32_t obj_id,drmModeAtomicReq * req,va_list args)287 void DRMPlaneManager::Perform(DRMOps code, uint32_t obj_id, drmModeAtomicReq *req, va_list args) {
288 auto plane = GetObject(obj_id);
289 if (plane == nullptr) {
290 DRM_LOGE("Invalid plane id %d", obj_id);
291 return;
292 }
293
294 if (code == DRMOps::PLANE_SET_SCALER_CONFIG) {
295 if (plane->ConfigureScalerLUT(dir_lut_blob_id_, cir_lut_blob_id_,
296 sep_lut_blob_id_)) {
297 DRM_LOGD("Plane %d: Configuring scaler LUTs", obj_id);
298 }
299 }
300
301 plane->Perform(code, req, args);
302 }
303
Perform(DRMOps code,drmModeAtomicReq * req,uint32_t obj_id,...)304 void DRMPlaneManager::Perform(DRMOps code, drmModeAtomicReq *req, uint32_t obj_id, ...) {
305 lock_guard<mutex> lock(lock_);
306 va_list args;
307 va_start(args, obj_id);
308 Perform(code, obj_id, req, args);
309 va_end(args);
310 }
311
GetPlanesInfo(DRMPlanesInfo * info)312 void DRMPlaneManager::GetPlanesInfo(DRMPlanesInfo *info) {
313 for (auto &plane : object_pool_) {
314 info->push_back(std::make_pair(plane.first, plane.second->GetPlaneTypeInfo()));
315 }
316 }
317
UnsetUnusedResources(uint32_t crtc_id,bool is_commit,drmModeAtomicReq * req)318 void DRMPlaneManager::UnsetUnusedResources(uint32_t crtc_id, bool is_commit, drmModeAtomicReq *req) {
319 // Unset planes that were assigned to the crtc referred to by crtc_id but are not requested
320 // in this round
321 lock_guard<mutex> lock(lock_);
322 for (auto &plane : object_pool_) {
323 uint32_t assigned_crtc = 0;
324 uint32_t requested_crtc = 0;
325 plane.second->GetAssignedCrtc(&assigned_crtc);
326 plane.second->GetRequestedCrtc(&requested_crtc);
327 if (assigned_crtc == crtc_id && requested_crtc == 0) {
328 plane.second->Unset(is_commit, req);
329 } else if (requested_crtc == crtc_id) {
330 // Plane is acquired, call reset color luts, which will reset if needed
331 plane.second->ResetColorLUTs(is_commit, req);
332 }
333 }
334 }
335
RetainPlanes(uint32_t crtc_id)336 void DRMPlaneManager::RetainPlanes(uint32_t crtc_id) {
337 for (auto &plane : object_pool_) {
338 uint32_t assigned_crtc = 0;
339 plane.second->GetAssignedCrtc(&assigned_crtc);
340 if (assigned_crtc == crtc_id) {
341 // Pretend this plane was requested by client
342 plane.second->SetRequestedCrtc(crtc_id);
343 const uint32_t plane_id = plane.first;
344 DRM_LOGD("Plane %d: Retaining on CRTC %d", plane_id, crtc_id);
345 }
346 }
347 }
348
PostValidate(uint32_t crtc_id)349 void DRMPlaneManager::PostValidate(uint32_t crtc_id) {
350 lock_guard<mutex> lock(lock_);
351 for (auto &plane : object_pool_) {
352 plane.second->PostValidate(crtc_id);
353 }
354 }
355
PostCommit(uint32_t crtc_id,bool success)356 void DRMPlaneManager::PostCommit(uint32_t crtc_id, bool success) {
357 lock_guard<mutex> lock(lock_);
358 DRM_LOGD("crtc %d", crtc_id);
359 for (auto &plane : object_pool_) {
360 plane.second->PostCommit(crtc_id, success);
361 }
362 }
363
SetScalerLUT(const DRMScalerLUTInfo & lut_info)364 void DRMPlaneManager::SetScalerLUT(const DRMScalerLUTInfo &lut_info) {
365 if (lut_info.dir_lut_size) {
366 drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.dir_lut),
367 lut_info.dir_lut_size, &dir_lut_blob_id_);
368 }
369 if (lut_info.cir_lut_size) {
370 drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.cir_lut),
371 lut_info.cir_lut_size, &cir_lut_blob_id_);
372 }
373 if (lut_info.sep_lut_size) {
374 drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.sep_lut),
375 lut_info.sep_lut_size, &sep_lut_blob_id_);
376 }
377 }
378
UnsetScalerLUT()379 void DRMPlaneManager::UnsetScalerLUT() {
380 if (dir_lut_blob_id_) {
381 drmModeDestroyPropertyBlob(fd_, dir_lut_blob_id_);
382 dir_lut_blob_id_ = 0;
383 }
384 if (cir_lut_blob_id_) {
385 drmModeDestroyPropertyBlob(fd_, cir_lut_blob_id_);
386 cir_lut_blob_id_ = 0;
387 }
388 if (sep_lut_blob_id_) {
389 drmModeDestroyPropertyBlob(fd_, sep_lut_blob_id_);
390 sep_lut_blob_id_ = 0;
391 }
392 }
393
394 // ==============================================================================================//
395
396 #undef __CLASS__
397 #define __CLASS__ "DRMPlane"
398
DRMPlane(int fd,uint32_t priority)399 DRMPlane::DRMPlane(int fd, uint32_t priority)
400 : DRMObject(prop_mgr_), fd_(fd), priority_(priority) {}
401
~DRMPlane()402 DRMPlane::~DRMPlane() {
403 drmModeFreePlane(drm_plane_);
404 }
405
GetTypeInfo(const PropertyMap & prop_map)406 void DRMPlane::GetTypeInfo(const PropertyMap &prop_map) {
407 uint64_t blob_id = 0;
408 drmModePropertyRes *prop = nullptr;
409 DRMPlaneTypeInfo *info = &plane_type_info_;
410 // Ideally we should check if this property type is a blob and then proceed.
411 std::tie(blob_id, prop) = prop_map.at(DRMProperty::CAPABILITIES);
412 drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
413 if (!blob) {
414 return;
415 }
416
417 if (!blob->data) {
418 return;
419 }
420
421 char *fmt_str = new char[blob->length + 1];
422 memcpy (fmt_str, blob->data, blob->length);
423 fmt_str[blob->length] = '\0';
424
425 info->max_linewidth = 2560;
426 info->max_scaler_linewidth = MAX_SCALER_LINEWIDTH;
427 info->max_upscale = 1;
428 info->max_downscale = 1;
429 info->max_horizontal_deci = 0;
430 info->max_vertical_deci = 0;
431 info->master_plane_id = 0;
432 if (info->type == DRMPlaneType::CURSOR) {
433 info->max_linewidth = 128;
434 }
435 // TODO(user): change default to V2 once we start getting V3 via capabilities blob
436 info->qseed3_version = QSEEDStepVersion::V3;
437 info->has_excl_rect = has_excl_rect_;
438
439 // We may have multiple lines with each one dedicated for something specific
440 // like formats etc
441 stringstream stream(fmt_str);
442 DRM_LOGI("stream str %s len %zu blob str %s len %d", stream.str().c_str(), stream.str().length(),
443 static_cast<const char *>(blob->data), blob->length);
444
445 string line = {};
446 string pixel_formats = "pixel_formats=";
447 string max_linewidth = "max_linewidth=";
448 string max_upscale = "max_upscale=";
449 string max_downscale = "max_downscale=";
450 string max_horizontal_deci = "max_horizontal_deci=";
451 string max_vertical_deci = "max_vertical_deci=";
452 string master_plane_id = "primary_smart_plane_id=";
453 string max_pipe_bw = "max_per_pipe_bw=";
454 string max_pipe_bw_high = "max_per_pipe_bw_high=";
455 string scaler_version = "scaler_step_ver=";
456 string block_sec_ui = "block_sec_ui=";
457 string true_inline_rot_rev = "true_inline_rot_rev=";
458 string inline_rot_pixel_formats = "inline_rot_pixel_formats=";
459 string true_inline_dwnscale_rt_numerator = "true_inline_dwnscale_rt_numerator=";
460 string true_inline_dwnscale_rt_denominator = "true_inline_dwnscale_rt_denominator=";
461 string true_inline_max_height = "true_inline_max_height=";
462
463 while (std::getline(stream, line)) {
464 if (line.find(inline_rot_pixel_formats) != string::npos) {
465 vector<pair<uint32_t, uint64_t>> inrot_formats_supported;
466 ParseFormats(line.erase(0, inline_rot_pixel_formats.length()), &inrot_formats_supported);
467 info->inrot_fmts_supported = std::move(inrot_formats_supported);
468 } else if (line.find(pixel_formats) != string::npos) {
469 vector<pair<uint32_t, uint64_t>> formats_supported;
470 ParseFormats(line.erase(0, pixel_formats.length()), &formats_supported);
471 info->formats_supported = std::move(formats_supported);
472 } else if (line.find(max_linewidth) != string::npos) {
473 info->max_linewidth = std::stoi(line.erase(0, max_linewidth.length()));
474 } else if (line.find(max_upscale) != string::npos) {
475 info->max_upscale = std::stoi(line.erase(0, max_upscale.length()));
476 } else if (line.find(max_downscale) != string::npos) {
477 info->max_downscale = std::stoi(line.erase(0, max_downscale.length()));
478 } else if (line.find(max_horizontal_deci) != string::npos) {
479 info->max_horizontal_deci = std::stoi(line.erase(0, max_horizontal_deci.length()));
480 } else if (line.find(max_vertical_deci) != string::npos) {
481 info->max_vertical_deci = std::stoi(line.erase(0, max_vertical_deci.length()));
482 } else if (line.find(master_plane_id) != string::npos) {
483 info->master_plane_id = std::stoi(line.erase(0, master_plane_id.length()));
484 DRM_LOGI("info->master_plane_id: detected master_plane=%d", info->master_plane_id);
485 } else if (line.find(max_pipe_bw) != string::npos) {
486 info->max_pipe_bandwidth = std::stoull(line.erase(0, max_pipe_bw.length()));
487 } else if (line.find(max_pipe_bw_high) != string::npos) {
488 info->max_pipe_bandwidth_high = std::stoull(line.erase(0, max_pipe_bw_high.length()));
489 } else if (line.find(scaler_version) != string::npos) {
490 info->qseed3_version =
491 PopulateQseedStepVersion(std::stoi(line.erase(0, scaler_version.length())));
492 } else if (line.find(block_sec_ui) != string::npos) {
493 info->block_sec_ui = !!(std::stoi(line.erase(0, block_sec_ui.length())));
494 } else if (line.find(true_inline_rot_rev) != string::npos) {
495 info->inrot_version =
496 PopulateInlineRotationVersion(std::stoi(line.erase(0, true_inline_rot_rev.length())));
497 } else if (line.find(true_inline_dwnscale_rt_numerator) != string::npos) {
498 info->true_inline_dwnscale_rt_num = std::stof(line.erase(0,
499 true_inline_dwnscale_rt_numerator.length()));
500 } else if (line.find(true_inline_dwnscale_rt_denominator) != string::npos) {
501 info->true_inline_dwnscale_rt_denom = std::stof(line.erase(0,
502 true_inline_dwnscale_rt_denominator.length()));
503 } else if (line.find(true_inline_max_height) != string::npos) {
504 info->max_rotation_linewidth = std::stoi(line.erase(0, true_inline_max_height.length()));
505 }
506 }
507
508 // TODO(user): Get max_scaler_linewidth and non_scaler_linewidth from driver
509 // max_linewidth can be smaller than 2560 for few target, so make sure to assign the minimum of both
510 info->max_scaler_linewidth = (info->qseed3_version < QSEEDStepVersion::V4) ? info->max_linewidth :
511 std::min((uint32_t)MAX_SCALER_LINEWIDTH, info->max_linewidth);
512
513 drmModeFreePropertyBlob(blob);
514 delete[] fmt_str;
515 }
516
ParseProperties()517 void DRMPlane::ParseProperties() {
518 // Map of property name to current value and property info pointer
519 PropertyMap prop_map;
520 bool csc = false;
521 bool scaler = false;
522 bool cursor = false;
523 drmModeObjectProperties *props =
524 drmModeObjectGetProperties(fd_, drm_plane_->plane_id, DRM_MODE_OBJECT_PLANE);
525 if (!props || !props->props || !props->prop_values) {
526 drmModeFreeObjectProperties(props);
527 return;
528 }
529
530 for (uint32_t j = 0; j < props->count_props; j++) {
531 drmModePropertyRes *info = drmModeGetProperty(fd_, props->props[j]);
532 if (!info) {
533 continue;
534 }
535
536 string property_name(info->name);
537 DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name);
538 if (prop_enum == DRMProperty::INVALID) {
539 DRM_LOGD("DRMProperty %s missing from global property mapping", info->name);
540 drmModeFreeProperty(info);
541 continue;
542 }
543
544 if (prop_enum == DRMProperty::EXCL_RECT) {
545 has_excl_rect_ = true;
546 }
547 if (prop_enum == DRMProperty::ROTATION) {
548 PopulateReflect(info);
549 } else if (prop_enum == DRMProperty::FB_TRANSLATION_MODE) {
550 PopulateSecureModes(info);
551 } else if (prop_enum == DRMProperty::MULTIRECT_MODE) {
552 PopulateMultiRectModes(info);
553 plane_type_info_.multirect_prop_present = true;
554 }
555
556 prop_mgr_.SetPropertyId(prop_enum, info->prop_id);
557 prop_map[prop_enum] = std::make_tuple(props->prop_values[j], info);
558 csc = prop_enum == DRMProperty::CSC_V1 ? true : csc;
559 scaler = (prop_enum == DRMProperty::SCALER_V1 || prop_enum == DRMProperty::SCALER_V2) \
560 ? true : scaler;
561 cursor = (prop_enum == DRMProperty::TYPE && props->prop_values[j] == DRM_PLANE_TYPE_CURSOR) \
562 ? true : cursor;
563
564 // Tone mapping properties.
565 if (prop_enum == DRMProperty::INVERSE_PMA) {
566 plane_type_info_.inverse_pma = true;
567 }
568
569 if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::CSC_DMA_V1 &&
570 (uint32_t)prop_enum <= (uint32_t)DRMProperty::CSC_DMA_V1) {
571 plane_type_info_.dgm_csc_version =
572 ((uint32_t)prop_enum - (uint32_t)DRMProperty::CSC_DMA_V1 + 1);
573 }
574
575 if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5 &&
576 (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5) {
577 plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::DMA_1D_IGC] =
578 ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5 + 5);
579 }
580 if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5 &&
581 (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5) {
582 plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::DMA_1D_GC] =
583 ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5 + 5);
584 }
585 if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V5 &&
586 (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V6) {
587 plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::VIG_1D_IGC] =
588 ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V5 + 5);
589 }
590 if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5 &&
591 (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V6) {
592 plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::VIG_3D_GAMUT] =
593 ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5 + 5);
594 }
595 }
596
597 DRMPlaneType type = DRMPlaneType::DMA;
598 if (csc && scaler) {
599 type = DRMPlaneType::VIG;
600 } else if (cursor) {
601 type = DRMPlaneType::CURSOR;
602 }
603
604 plane_type_info_.type = type;
605 GetTypeInfo(prop_map);
606
607 for (auto &prop : prop_map) {
608 drmModeFreeProperty(std::get<1>(prop.second));
609 }
610
611 drmModeFreeObjectProperties(props);
612 }
613
InitAndParse(drmModePlane * plane)614 void DRMPlane::InitAndParse(drmModePlane *plane) {
615 drm_plane_ = plane;
616 ParseProperties();
617
618 unique_ptr<DRMPPManager> pp_mgr(new DRMPPManager(fd_));
619 pp_mgr_ = std::move(pp_mgr);
620 pp_mgr_->Init(prop_mgr_, DRM_MODE_OBJECT_PLANE);
621 }
622
ConfigureScalerLUT(uint32_t dir_lut_blob_id,uint32_t cir_lut_blob_id,uint32_t sep_lut_blob_id)623 bool DRMPlane::ConfigureScalerLUT(uint32_t dir_lut_blob_id,
624 uint32_t cir_lut_blob_id, uint32_t sep_lut_blob_id) {
625 if (plane_type_info_.type != DRMPlaneType::VIG || is_lut_configured_) {
626 return false;
627 }
628
629 if (dir_lut_blob_id) {
630 AddProperty(DRMProperty::LUT_ED, dir_lut_blob_id, true);
631 }
632 if (cir_lut_blob_id) {
633 AddProperty(DRMProperty::LUT_CIR, cir_lut_blob_id, true);
634 }
635 if (sep_lut_blob_id) {
636 AddProperty(DRMProperty::LUT_SEP, sep_lut_blob_id, true);
637 }
638
639 return true;
640 }
641
SetExclRect(DRMRect rect)642 void DRMPlane::SetExclRect(DRMRect rect) {
643 drm_clip_rect clip_rect;
644 SetRect(rect, &clip_rect);
645 excl_rect_copy_ = clip_rect;
646 AddProperty(DRMProperty::EXCL_RECT,
647 reinterpret_cast<uint64_t>(&excl_rect_copy_), true);
648 DRM_LOGD("Plane %d: Setting exclusion rect [x,y,w,h][%d,%d,%d,%d]", drm_plane_->plane_id,
649 clip_rect.x1, clip_rect.y1, (clip_rect.x2 - clip_rect.x1),
650 (clip_rect.y2 - clip_rect.y1));
651 }
652
SetCscConfig(DRMCscType csc_type)653 bool DRMPlane::SetCscConfig(DRMCscType csc_type) {
654 if (plane_type_info_.type != DRMPlaneType::VIG) {
655 return false;
656 }
657
658 if (csc_type > kCscTypeMax) {
659 return false;
660 }
661
662 if (!prop_mgr_.IsPropertyAvailable(DRMProperty::CSC_V1)) {
663 return false;
664 }
665
666 if (csc_type == kCscTypeMax) {
667 AddProperty(DRMProperty::CSC_V1, 0);
668 } else {
669 csc_config_copy_ = csc_10bit_convert[csc_type];
670 AddProperty(DRMProperty::CSC_V1,
671 reinterpret_cast<uint64_t>(&csc_config_copy_), true);
672 }
673
674 return true;
675 }
676
SetScalerConfig(uint64_t handle)677 bool DRMPlane::SetScalerConfig(uint64_t handle) {
678 if (plane_type_info_.type != DRMPlaneType::VIG) {
679 return false;
680 }
681
682 if (prop_mgr_.IsPropertyAvailable(DRMProperty::SCALER_V2)) {
683 sde_drm_scaler_v2 *scaler_v2_config = reinterpret_cast<sde_drm_scaler_v2 *>(handle);
684 uint64_t scaler_data = 0;
685 // The address needs to be valid even after async commit, since we are sending address to
686 // driver directly, instead of blob. So we need to copy over contents that client sent. Client
687 // may have sent an address of object on stack which will be released after this call.
688 scaler_v2_config_copy_ = *scaler_v2_config;
689 if (scaler_v2_config_copy_.enable) {
690 scaler_data = reinterpret_cast<uint64_t>(&scaler_v2_config_copy_);
691 }
692 AddProperty(DRMProperty::SCALER_V2, scaler_data, scaler_data != 0);
693 return true;
694 }
695
696 return false;
697 }
698
SetDecimation(DRMProperty prop,uint32_t prop_value)699 void DRMPlane::SetDecimation(DRMProperty prop, uint32_t prop_value) {
700 if (plane_type_info_.type == DRMPlaneType::DMA || plane_type_info_.master_plane_id) {
701 // if value is 0, client is just trying to clear previous decimation, so bail out silently
702 if (prop_value > 0) {
703 DRM_LOGE("Plane %d: Setting decimation %d is not supported.", drm_plane_->plane_id,
704 prop_value);
705 }
706 return;
707 }
708
709 // TODO(user): Currently a ViG plane in smart DMA mode could receive a non-zero decimation value
710 // but there is no good way to catch. In any case fix will be in client
711 AddProperty(prop, prop_value);
712 DRM_LOGD("Plane %d: Setting decimation %d", drm_plane_->plane_id, prop_value);
713 }
714
PostValidate(uint32_t crtc_id)715 void DRMPlane::PostValidate(uint32_t crtc_id) {
716 DiscardDirtyProperties();
717 if (requested_crtc_id_ == crtc_id) {
718 SetRequestedCrtc(0);
719 }
720 }
721
PostCommit(uint32_t crtc_id,bool success)722 void DRMPlane::PostCommit(uint32_t crtc_id, bool success) {
723 DRM_LOGD("crtc %d", crtc_id);
724 if (!success) {
725 // To reset
726 PostValidate(crtc_id);
727 return;
728 }
729
730 uint32_t assigned_crtc = 0;
731 uint32_t requested_crtc = 0;
732
733 CommitProperties();
734 GetAssignedCrtc(&assigned_crtc);
735 GetRequestedCrtc(&requested_crtc);
736
737 // In future, it is possible that plane is already attached in case of continuous splash. This
738 // will cause the first commit to only unstage pipes. We want to mark luts as configured only
739 // when they really are, which typically happens if a crtc is requested for a plane
740 if (requested_crtc == crtc_id && !is_lut_configured_) {
741 is_lut_configured_ = true;
742 }
743
744 if (requested_crtc && assigned_crtc && requested_crtc != assigned_crtc) {
745 // We should never be here
746 DRM_LOGE("Found plane %d switching from crtc %d to crtc %d", drm_plane_->plane_id,
747 assigned_crtc, requested_crtc);
748 }
749
750 // If we have set a pipe OR unset a pipe during commit, update states
751 if (requested_crtc == crtc_id || assigned_crtc == crtc_id) {
752 SetAssignedCrtc(requested_crtc);
753 SetRequestedCrtc(0);
754 }
755 }
756
Perform(DRMOps code,drmModeAtomicReq * req,va_list args)757 void DRMPlane::Perform(DRMOps code, drmModeAtomicReq *req, va_list args) {
758 uint32_t obj_id = drm_plane_->plane_id;
759
760 switch (code) {
761 // TODO(user): Check if these exist in map before attempting to access
762 case DRMOps::PLANE_SET_SRC_RECT: {
763 DRMRect rect = va_arg(args, DRMRect);
764 // source co-ordinates accepted by DRM are 16.16 fixed point
765 AddProperty(DRMProperty::SRC_X, rect.left << 16);
766 AddProperty(DRMProperty::SRC_Y, rect.top << 16);
767 AddProperty(DRMProperty::SRC_W, (rect.right - rect.left) << 16);
768 AddProperty(DRMProperty::SRC_H, (rect.bottom - rect.top) << 16);
769 DRM_LOGV("Plane %d: Setting crop [x,y,w,h][%d,%d,%d,%d]", obj_id, rect.left,
770 rect.top, (rect.right - rect.left), (rect.bottom - rect.top));
771 } break;
772
773 case DRMOps::PLANE_SET_DST_RECT: {
774 DRMRect rect = va_arg(args, DRMRect);
775 AddProperty(DRMProperty::CRTC_X, rect.left);
776 AddProperty(DRMProperty::CRTC_Y, rect.top);
777 AddProperty(DRMProperty::CRTC_W, (rect.right - rect.left));
778 AddProperty(DRMProperty::CRTC_H, (rect.bottom - rect.top));
779 DRM_LOGV("Plane %d: Setting dst [x,y,w,h][%d,%d,%d,%d]", obj_id, rect.left,
780 rect.top, (rect.right - rect.left), (rect.bottom - rect.top));
781 } break;
782 case DRMOps::PLANE_SET_EXCL_RECT: {
783 DRMRect excl_rect = va_arg(args, DRMRect);
784 SetExclRect(excl_rect);
785 } break;
786
787 case DRMOps::PLANE_SET_ZORDER: {
788 uint32_t zpos = va_arg(args, uint32_t);
789 AddProperty(DRMProperty::ZPOS, zpos);
790 DRM_LOGD("Plane %d: Setting z %d", obj_id, zpos);
791 } break;
792
793 case DRMOps::PLANE_SET_ROTATION: {
794 uint32_t rot_bit_mask = va_arg(args, uint32_t);
795 uint32_t drm_rot_bit_mask = 0;
796 if (rot_bit_mask & static_cast<uint32_t>(DRMRotation::FLIP_H)) {
797 drm_rot_bit_mask |= 1 << REFLECT_X;
798 }
799 if (rot_bit_mask & static_cast<uint32_t>(DRMRotation::FLIP_V)) {
800 drm_rot_bit_mask |= 1 << REFLECT_Y;
801 }
802 if (rot_bit_mask & static_cast<uint32_t>(DRMRotation::ROT_90)) {
803 drm_rot_bit_mask |= 1 << ROTATE_90;
804 } else {
805 drm_rot_bit_mask |= 1 << ROTATE_0;
806 }
807 AddProperty(DRMProperty::ROTATION, drm_rot_bit_mask);
808 DRM_LOGV("Plane %d: Setting rotation mask %x", obj_id, drm_rot_bit_mask);
809 } break;
810
811 case DRMOps::PLANE_SET_ALPHA: {
812 uint32_t alpha = va_arg(args, uint32_t);
813 AddProperty(DRMProperty::ALPHA, alpha);
814 DRM_LOGV("Plane %d: Setting alpha %d", obj_id, alpha);
815 } break;
816
817 case DRMOps::PLANE_SET_BLEND_TYPE: {
818 uint32_t blending = va_arg(args, uint32_t);
819 AddProperty(DRMProperty::BLEND_OP, blending);
820 DRM_LOGV("Plane %d: Setting blending %d", obj_id, blending);
821 } break;
822
823 case DRMOps::PLANE_SET_H_DECIMATION: {
824 uint32_t deci = va_arg(args, uint32_t);
825 SetDecimation(DRMProperty::H_DECIMATE, deci);
826 } break;
827
828 case DRMOps::PLANE_SET_V_DECIMATION: {
829 uint32_t deci = va_arg(args, uint32_t);
830 SetDecimation(DRMProperty::V_DECIMATE, deci);
831 } break;
832
833 case DRMOps::PLANE_SET_SRC_CONFIG: {
834 bool src_config = va_arg(args, uint32_t);
835 AddProperty(DRMProperty::SRC_CONFIG, src_config);
836 DRM_LOGV("Plane %d: Setting src_config flags-%x", obj_id, src_config);
837 } break;
838
839 case DRMOps::PLANE_SET_CRTC: {
840 uint32_t crtc_id = va_arg(args, uint32_t);
841 AddProperty(DRMProperty::CRTC_ID, crtc_id);
842 SetRequestedCrtc(crtc_id);
843 DRM_LOGV("Plane %d: Setting crtc %d", obj_id, crtc_id);
844 } break;
845
846 case DRMOps::PLANE_SET_FB_ID: {
847 uint32_t fb_id = va_arg(args, uint32_t);
848 AddProperty(DRMProperty::FB_ID, fb_id);
849 DRM_LOGV("Plane %d: Setting fb_id %d", obj_id, fb_id);
850 } break;
851
852 case DRMOps::PLANE_SET_ROT_FB_ID: {
853 uint32_t fb_id = va_arg(args, uint32_t);
854 AddProperty(DRMProperty::ROT_FB_ID, fb_id, true);
855 DRM_LOGV("Plane %d: Setting rot_fb_id %d", obj_id, fb_id);
856 } break;
857
858 case DRMOps::PLANE_SET_INPUT_FENCE: {
859 int fence = va_arg(args, int);
860 AddProperty(DRMProperty::INPUT_FENCE, fence, true);
861 DRM_LOGV("Plane %d: Setting input fence %d", obj_id, fence);
862 } break;
863
864 case DRMOps::PLANE_SET_SCALER_CONFIG: {
865 uint64_t handle = va_arg(args, uint64_t);
866 if (SetScalerConfig(handle)) {
867 DRM_LOGV("Plane %d: Setting scaler config", obj_id);
868 }
869 } break;
870
871 case DRMOps::PLANE_SET_FB_SECURE_MODE: {
872 int secure_mode = va_arg(args, int);
873 uint32_t fb_secure_mode = NON_SECURE;
874 switch (secure_mode) {
875 case (int)DRMSecureMode::NON_SECURE:
876 fb_secure_mode = NON_SECURE;
877 break;
878 case (int)DRMSecureMode::SECURE:
879 fb_secure_mode = SECURE;
880 break;
881 case (int)DRMSecureMode::NON_SECURE_DIR_TRANSLATION:
882 fb_secure_mode = NON_SECURE_DIR_TRANSLATION;
883 break;
884 case (int)DRMSecureMode::SECURE_DIR_TRANSLATION:
885 fb_secure_mode = SECURE_DIR_TRANSLATION;
886 break;
887 default:
888 DRM_LOGE("Invalid secure mode %d to set on plane %d", secure_mode, obj_id);
889 break;
890 }
891
892 AddProperty(DRMProperty::FB_TRANSLATION_MODE, fb_secure_mode);
893 DRM_LOGD("Plane %d: Setting FB secure mode %d", obj_id, fb_secure_mode);
894 } break;
895
896 case DRMOps::PLANE_SET_CSC_CONFIG: {
897 uint32_t* csc_type = va_arg(args, uint32_t*);
898 if (csc_type) {
899 SetCscConfig((DRMCscType)*csc_type);
900 }
901 } break;
902
903 case DRMOps::PLANE_SET_MULTIRECT_MODE: {
904 DRMMultiRectMode drm_multirect_mode = (DRMMultiRectMode)va_arg(args, uint32_t);
905 SetMultiRectMode(drm_multirect_mode);
906 } break;
907
908 case DRMOps::PLANE_SET_INVERSE_PMA: {
909 uint32_t pma = va_arg(args, uint32_t);
910 AddProperty(DRMProperty::INVERSE_PMA, pma);
911 DRM_LOGD("Plane %d: %s inverse pma", obj_id, pma ? "Setting" : "Resetting");
912 } break;
913
914 case DRMOps::PLANE_SET_DGM_CSC_CONFIG: {
915 uint64_t handle = va_arg(args, uint64_t);
916 if (SetDgmCscConfig(handle)) {
917 DRM_LOGD("Plane %d: Setting Csc Lut config", obj_id);
918 }
919 } break;
920
921 case DRMOps::PLANE_SET_POST_PROC: {
922 DRMPPFeatureInfo *data = va_arg(args, DRMPPFeatureInfo*);
923 if (data) {
924 DRM_LOGD("Plane %d: Set post proc feature id - %d", obj_id, data->id);
925 pp_mgr_->SetPPFeature(req, obj_id, *data);
926 UpdatePPLutFeatureInuse(data);
927 }
928 } break;
929
930 case DRMOps::PLANE_SET_SSPP_LAYOUT: {
931 if (!prop_mgr_.IsPropertyAvailable(DRMProperty::SDE_SSPP_LAYOUT)) {
932 DRM_LOGD("SSPP_LAYOUT property isn't exposed");
933 break;
934 }
935 DRMSSPPLayoutIndex layout_index = (DRMSSPPLayoutIndex) va_arg(args, uint32_t);
936 AddProperty(DRMProperty::SDE_SSPP_LAYOUT, (uint32_t)layout_index);
937 DRM_LOGD("Plane %d: Setting SSPP Layout to %d", obj_id, layout_index);
938 } break;
939
940 default:
941 DRM_LOGE("Invalid opcode %d for DRM Plane %d", code, obj_id);
942 }
943 }
944
UpdatePPLutFeatureInuse(DRMPPFeatureInfo * data)945 void DRMPlane::UpdatePPLutFeatureInuse(DRMPPFeatureInfo *data) {
946 DRMTonemapLutType lut_type = {};
947 bool ret = GetDRMonemapLutTypeFromPPFeatureID(data->id, &lut_type);
948 if (ret == false) {
949 DRM_LOGE("Failed to get the lut type from PPFeatureID = %d", data->id);
950 return;
951 }
952
953 const auto state = data->payload ? kActive : kInactive;
954
955 switch (lut_type) {
956 case DRMTonemapLutType::DMA_1D_GC:
957 dgm_1d_lut_gc_state_ = state;
958 break;
959 case DRMTonemapLutType::DMA_1D_IGC:
960 dgm_1d_lut_igc_state_ = state;
961 break;
962 case DRMTonemapLutType::VIG_1D_IGC:
963 vig_1d_lut_igc_state_ = state;
964 break;
965 case DRMTonemapLutType::VIG_3D_GAMUT:
966 vig_3d_lut_gamut_state_ = state;
967 break;
968 default:
969 DRM_LOGE("Invalid lut_type = %d state = %d", lut_type, state);
970 }
971 return;
972 }
973
PerformWrapper(DRMOps code,drmModeAtomicReq * req,...)974 void DRMPlane::PerformWrapper(DRMOps code, drmModeAtomicReq *req, ...) {
975 va_list args;
976 va_start(args, req);
977 Perform(code, req, args);
978 va_end(args);
979 }
980
Dump()981 void DRMPlane::Dump() {
982 DRM_LOGE(
983 "id: %d\tcrtc id: %d\tfb id: %d\tCRTC_xy: %dx%d\txy: %dx%d\tgamma "
984 "size: %d\tpossible crtc: 0x%x\n",
985 drm_plane_->plane_id, drm_plane_->crtc_id, drm_plane_->fb_id, drm_plane_->crtc_x,
986 drm_plane_->crtc_y, drm_plane_->x, drm_plane_->y, drm_plane_->gamma_size,
987 drm_plane_->possible_crtcs);
988 DRM_LOGE("Format Suported: \n");
989 for (uint32_t i = 0; i < (uint32_t)drm_plane_->count_formats; i++)
990 DRM_LOGE(" %4.4s", (char *)&drm_plane_->formats[i]);
991 }
992
SetMultiRectMode(DRMMultiRectMode drm_multirect_mode)993 void DRMPlane::SetMultiRectMode(DRMMultiRectMode drm_multirect_mode) {
994 if (!plane_type_info_.multirect_prop_present) {
995 return;
996 }
997 uint32_t obj_id = drm_plane_->plane_id;
998 uint32_t multirect_mode = MULTIRECT_NONE;
999 switch (drm_multirect_mode) {
1000 case DRMMultiRectMode::NONE:
1001 multirect_mode = MULTIRECT_NONE;
1002 break;
1003 case DRMMultiRectMode::PARALLEL:
1004 multirect_mode = MULTIRECT_PARALLEL;
1005 break;
1006 case DRMMultiRectMode::SERIAL:
1007 multirect_mode = MULTIRECT_SERIAL;
1008 break;
1009 default:
1010 DRM_LOGE("Invalid multirect mode %d to set on plane %d", drm_multirect_mode, GetObjectId());
1011 break;
1012 }
1013 AddProperty(DRMProperty::MULTIRECT_MODE, multirect_mode);
1014 DRM_LOGD("Plane %d: Setting multirect_mode %d", obj_id, multirect_mode);
1015 }
1016
Unset(bool is_commit,drmModeAtomicReq * req)1017 void DRMPlane::Unset(bool is_commit, drmModeAtomicReq *req) {
1018 DRM_LOGD("Plane %d: Unsetting from crtc %d", drm_plane_->plane_id, assigned_crtc_id_);
1019 PerformWrapper(DRMOps::PLANE_SET_FB_ID, req, 0);
1020 PerformWrapper(DRMOps::PLANE_SET_CRTC, req, 0);
1021 DRMRect rect = {0, 0, 0, 0};
1022 PerformWrapper(DRMOps::PLANE_SET_SRC_RECT, req, rect);
1023 PerformWrapper(DRMOps::PLANE_SET_DST_RECT, req, rect);
1024 PerformWrapper(DRMOps::PLANE_SET_EXCL_RECT, req, rect);
1025 if (plane_type_info_.inverse_pma) {
1026 PerformWrapper(DRMOps::PLANE_SET_INVERSE_PMA, req, 0);
1027 }
1028
1029 // Reset the sspp tonemap properties if they were set and update the in-use only if
1030 // its a Commit as Unset is called in Validate as well.
1031 if (dgm_csc_in_use_) {
1032 uint64_t csc_v1 = 0;
1033 AddProperty(DRMProperty::CSC_DMA_V1, csc_v1, true);
1034 DRM_LOGV("Plane %d Clearing DGM CSC", drm_plane_->plane_id);
1035 dgm_csc_in_use_ = !is_commit;
1036 }
1037 ResetColorLUTs(is_commit, req);
1038 }
1039
SetDgmCscConfig(uint64_t handle)1040 bool DRMPlane::SetDgmCscConfig(uint64_t handle) {
1041 if (plane_type_info_.type == DRMPlaneType::DMA &&
1042 prop_mgr_.IsPropertyAvailable(DRMProperty::CSC_DMA_V1)) {
1043 sde_drm_csc_v1 *csc_v1 = reinterpret_cast<sde_drm_csc_v1 *>(handle);
1044 uint64_t csc_v1_data = 0;
1045 sde_drm_csc_v1 csc_v1_tmp = {};
1046 csc_config_copy_ = *csc_v1;
1047 if (std::memcmp(&csc_config_copy_, &csc_v1_tmp, sizeof(sde_drm_csc_v1)) != 0) {
1048 csc_v1_data = reinterpret_cast<uint64_t>(&csc_config_copy_);
1049 }
1050 AddProperty(DRMProperty::CSC_DMA_V1, csc_v1_data, true);
1051 dgm_csc_in_use_ = (csc_v1_data != 0);
1052 DRM_LOGV("Plane %d in_use = %d", drm_plane_->plane_id, dgm_csc_in_use_);
1053
1054 return true;
1055 }
1056
1057 return false;
1058 }
1059
ResetColorLUTs(bool is_commit,drmModeAtomicReq * req)1060 void DRMPlane::ResetColorLUTs(bool is_commit, drmModeAtomicReq *req) {
1061 // Reset the color luts if they were set and update the state only if its a Commit as Unset
1062 // is called in Validate as well.
1063 for (int i = 0; i <= static_cast<int>(DRMTonemapLutType::VIG_3D_GAMUT); i++) {
1064 auto itr = plane_type_info_.tonemap_lut_version_map.find(static_cast<DRMTonemapLutType>(i));
1065 if (itr != plane_type_info_.tonemap_lut_version_map.end()) {
1066 ResetColorLUTState(static_cast<DRMTonemapLutType>(i), is_commit, req);
1067 }
1068 }
1069 }
1070
ResetColorLUTState(DRMTonemapLutType lut_type,bool is_commit,drmModeAtomicReq * req)1071 void DRMPlane::ResetColorLUTState(DRMTonemapLutType lut_type, bool is_commit,
1072 drmModeAtomicReq *req) {
1073 DRMPlaneLutState *lut_state = nullptr;
1074 DRMPPFeatureID feature_id = {};
1075 switch (lut_type) {
1076 case DRMTonemapLutType::DMA_1D_GC:
1077 lut_state = &dgm_1d_lut_gc_state_;
1078 feature_id = kFeatureDgmGc;
1079 break;
1080 case DRMTonemapLutType::DMA_1D_IGC:
1081 lut_state = &dgm_1d_lut_igc_state_;
1082 feature_id = kFeatureDgmIgc;
1083 break;
1084 case DRMTonemapLutType::VIG_1D_IGC:
1085 lut_state = &vig_1d_lut_igc_state_;
1086 feature_id = kFeatureVigIgc;
1087 break;
1088 case DRMTonemapLutType::VIG_3D_GAMUT:
1089 lut_state = &vig_3d_lut_gamut_state_;
1090 feature_id = kFeatureVigGamut;
1091 break;
1092 default:
1093 DLOGE("Invalid lut type = %d", lut_type);
1094 return;
1095 }
1096
1097 if (*lut_state == kInactive) {
1098 DRM_LOGV("Plane %d %s Lut not used", drm_plane_->plane_id, GetColorLutString(lut_type));
1099 return;
1100 }
1101
1102 DRMPlaneLutState target_state;
1103 // If plane is getting unset, clearing of LUT will not be applied in hw.
1104 // In that case, mark LUT as dirty and make sure that these are cleared the
1105 // next time the plane gets used
1106 if (*lut_state == kActive && requested_crtc_id_ == 0) {
1107 target_state = kDirty;
1108 } else if (*lut_state == kDirty && requested_crtc_id_ != 0) {
1109 // If plane is getting activated while LUT is in dirty state, the new state
1110 // should be inactive but still need to clear exiting LUT config in hw
1111 target_state = kInactive;
1112 } else {
1113 return;
1114 }
1115
1116 if (is_commit) {
1117 DRM_LOGD("Plane %d Clearing %s Lut, moving from (%d) -> (%d)", drm_plane_->plane_id,
1118 GetColorLutString(lut_type), *lut_state, target_state);
1119
1120 *lut_state = target_state;
1121 }
1122
1123 ResetColorLUT(feature_id, req);
1124 }
1125
ResetColorLUT(DRMPPFeatureID id,drmModeAtomicReq * req)1126 void DRMPlane::ResetColorLUT(DRMPPFeatureID id, drmModeAtomicReq *req) {
1127 DRMPPFeatureInfo pp_feature_info = {};
1128 pp_feature_info.type = kPropBlob;
1129 pp_feature_info.payload = nullptr;
1130 pp_feature_info.id = id;
1131 pp_mgr_->SetPPFeature(req, drm_plane_->plane_id, pp_feature_info);
1132 }
1133
1134 } // namespace sde_drm
1135