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