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