display: Move sde-drm to open source
- Update make file to compile sde-drm files.
- Update copyright and year of sde-drm files.
Change-Id: I8f3b60e79b0e8680e63bf4a076b43a30c5daf68b
CRs-Fixed: 2366253
diff --git a/sde-drm/drm_plane.cpp b/sde-drm/drm_plane.cpp
new file mode 100644
index 0000000..033aced
--- /dev/null
+++ b/sde-drm/drm_plane.cpp
@@ -0,0 +1,987 @@
+/*
+* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <drm.h>
+// The 3 headers above are a workaround to prevent kernel drm.h from being used that has the
+// "virtual" keyword used for a variable. In future replace libdrm version drm.h with kernel
+// version drm/drm.h
+#include <drm_logger.h>
+#include <drm/drm_fourcc.h>
+#include <drm/sde_drm.h>
+
+#include <cstring>
+#include <map>
+#include <sstream>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "drm_utils.h"
+#include "drm_plane.h"
+#include "drm_property.h"
+
+namespace sde_drm {
+
+using std::map;
+using std::string;
+using std::map;
+using std::pair;
+using std::vector;
+using std::unique_ptr;
+using std::tuple;
+using std::stringstream;
+
+static struct sde_drm_csc_v1 csc_10bit_convert[kCscTypeMax] = {
+ [kCscYuv2Rgb601L] = {
+ {
+ 0x12A000000, 0x000000000, 0x198800000,
+ 0x12A000000, 0x7F9B800000, 0x7F30000000,
+ 0x12A000000, 0x204800000, 0x000000000,
+ },
+ { 0xffc0, 0xfe00, 0xfe00,},
+ { 0x0, 0x0, 0x0,},
+ { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
+ { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+ },
+ [kCscYuv2Rgb601FR] = {
+ {
+ 0x100000000, 0x0, 0x167000000,
+ 0x100000000, 0x7fa8000000, 0x7f49000000,
+ 0x100000000, 0x1c5800000, 0x0,
+ },
+ { 0x0000, 0xfe00, 0xfe00,},
+ { 0x0, 0x0, 0x0,},
+ { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+ { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+ },
+ [kCscYuv2Rgb709L] = {
+ {
+ 0x12a000000, 0x0, 0x1cb000000,
+ 0x12a000000, 0x7fc9800000, 0x7f77800000,
+ 0x12a000000, 0x21d000000, 0x0,
+ },
+ { 0xffc0, 0xfe00, 0xfe00,},
+ { 0x0, 0x0, 0x0,},
+ { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
+ { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+ },
+ [kCscYuv2Rgb2020L] = {
+ {
+ 0x12b000000, 0x0, 0x1af000000,
+ 0x12b000000, 0x7fd0000000, 0x7f59000000,
+ 0x12b000000, 0x226000000, 0x0,
+ },
+ { 0xffc0, 0xfe00, 0xfe00,},
+ { 0x0, 0x0, 0x0,},
+ { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
+ { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+ },
+ [kCscYuv2Rgb2020FR] = {
+ {
+ 0x100000000, 0x0, 0x179800000,
+ 0x100000000, 0x7fd6000000, 0x7f6d800000,
+ 0x100000000, 0x1e1800000, 0x0,
+ },
+ { 0x0000, 0xfe00, 0xfe00,},
+ { 0x0, 0x0, 0x0,},
+ { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+ { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
+ },
+};
+
+static uint8_t REFLECT_X = 0;
+static uint8_t REFLECT_Y = 0;
+static uint8_t ROTATE_90 = 0;
+static uint8_t ROTATE_0 = 0;
+
+// FB Secure Modes
+static uint8_t NON_SECURE = 0;
+static uint8_t SECURE = 1;
+static uint8_t NON_SECURE_DIR_TRANSLATION = 2;
+static uint8_t SECURE_DIR_TRANSLATION = 3;
+
+// Multi rect modes
+static uint8_t MULTIRECT_NONE = 0;
+static uint8_t MULTIRECT_PARALLEL = 1;
+static uint8_t MULTIRECT_SERIAL = 2;
+
+static void SetRect(DRMRect &source, drm_clip_rect *target) {
+ target->x1 = uint16_t(source.left);
+ target->y1 = uint16_t(source.top);
+ target->x2 = uint16_t(source.right);
+ target->y2 = uint16_t(source.bottom);
+}
+
+static void PopulateReflect(drmModePropertyRes *prop) {
+ if (REFLECT_X) {
+ return;
+ }
+
+ if (!drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) {
+ return;
+ }
+
+ for (auto i = 0; i < prop->count_enums; i++) {
+ string enum_name(prop->enums[i].name);
+ if (enum_name == "reflect-x") {
+ REFLECT_X = prop->enums[i].value;
+ } else if (enum_name == "reflect-y") {
+ REFLECT_Y = prop->enums[i].value;
+ } else if (enum_name == "rotate-90") {
+ ROTATE_90 = prop->enums[i].value;
+ } else if (enum_name == "rotate-0") {
+ ROTATE_0 = prop->enums[i].value;
+ }
+ }
+}
+
+static void PopulateSecureModes(drmModePropertyRes *prop) {
+ static bool secure_modes_populated = false;
+ if (!secure_modes_populated) {
+ for (auto i = 0; i < prop->count_enums; i++) {
+ string enum_name(prop->enums[i].name);
+ if (enum_name == "non_sec") {
+ NON_SECURE = prop->enums[i].value;
+ } else if (enum_name == "sec") {
+ SECURE = prop->enums[i].value;
+ } else if (enum_name == "non_sec_direct_translation") {
+ NON_SECURE_DIR_TRANSLATION = prop->enums[i].value;
+ } else if (enum_name == "sec_direct_translation") {
+ SECURE_DIR_TRANSLATION = prop->enums[i].value;
+ }
+ }
+ secure_modes_populated = true;
+ }
+}
+
+static InlineRotationVersion PopulateInlineRotationVersion(uint32_t ver) {
+ switch (ver) {
+ case 0x0000: return InlineRotationVersion::kInlineRotationNone;
+ case 0x0001: return InlineRotationVersion::kInlineRotationV1;
+ default: return InlineRotationVersion::kInlineRotationNone;
+ }
+}
+
+static QSEEDStepVersion PopulateQseedStepVersion(uint32_t hw_ver) {
+ switch (hw_ver) {
+ case 0x1003: return QSEEDStepVersion::V3;
+ case 0x1004: return QSEEDStepVersion::V4;
+ case 0x2004: return QSEEDStepVersion::V3LITE_V4;
+ case 0x3000: return QSEEDStepVersion::V3LITE_V5;
+ // default value. also corresponds to (hw_ver == 0x1002)
+ default: return QSEEDStepVersion::V2;
+ }
+}
+
+static void PopulateMultiRectModes(drmModePropertyRes *prop) {
+ static bool multirect_modes_populated = false;
+ if (!multirect_modes_populated) {
+ for (auto i = 0; i < prop->count_enums; i++) {
+ string enum_name(prop->enums[i].name);
+ if (enum_name == "none") {
+ MULTIRECT_NONE = prop->enums[i].value;
+ } else if (enum_name == "parallel") {
+ MULTIRECT_PARALLEL = prop->enums[i].value;
+ } else if (enum_name == "serial") {
+ MULTIRECT_SERIAL = prop->enums[i].value;
+ }
+ }
+ multirect_modes_populated = true;
+ }
+}
+
+#define __CLASS__ "DRMPlaneManager"
+
+DRMPlaneManager::DRMPlaneManager(int fd) : fd_(fd) {}
+
+void DRMPlaneManager::Init() {
+ drmModePlaneRes *resource = drmModeGetPlaneResources(fd_);
+ if (!resource) {
+ return;
+ }
+
+ for (uint32_t i = 0; i < resource->count_planes; i++) {
+ // The enumeration order itself is the priority from high to low
+ unique_ptr<DRMPlane> plane(new DRMPlane(fd_, i));
+ drmModePlane *libdrm_plane = drmModeGetPlane(fd_, resource->planes[i]);
+ if (libdrm_plane) {
+ plane->InitAndParse(libdrm_plane);
+ plane_pool_[resource->planes[i]] = std::move(plane);
+ } else {
+ DRM_LOGE("Critical error: drmModeGetPlane() failed for plane %d.", resource->planes[i]);
+ }
+ }
+
+ drmModeFreePlaneResources(resource);
+}
+
+void DRMPlaneManager::DumpByID(uint32_t id) {
+ plane_pool_.at(id)->Dump();
+}
+
+void DRMPlaneManager::Perform(DRMOps code, uint32_t obj_id, drmModeAtomicReq *req, va_list args) {
+ auto it = plane_pool_.find(obj_id);
+ if (it == plane_pool_.end()) {
+ DRM_LOGE("Invalid plane id %d", obj_id);
+ return;
+ }
+
+ if (code == DRMOps::PLANE_SET_SCALER_CONFIG) {
+ if (it->second->ConfigureScalerLUT(req, dir_lut_blob_id_, cir_lut_blob_id_,
+ sep_lut_blob_id_)) {
+ DRM_LOGD("Plane %d: Configuring scaler LUTs", obj_id);
+ }
+ }
+
+ it->second->Perform(code, req, args);
+}
+
+void DRMPlaneManager::Perform(DRMOps code, drmModeAtomicReq *req, uint32_t obj_id, ...) {
+ va_list args;
+ va_start(args, obj_id);
+ Perform(code, obj_id, req, args);
+ va_end(args);
+}
+
+void DRMPlaneManager::DumpAll() {
+ for (uint32_t i = 0; i < plane_pool_.size(); i++) {
+ plane_pool_[i]->Dump();
+ }
+}
+
+void DRMPlaneManager::GetPlanesInfo(DRMPlanesInfo *info) {
+ for (auto &plane : plane_pool_) {
+ info->push_back(std::make_pair(plane.first, plane.second->GetPlaneTypeInfo()));
+ }
+}
+
+void DRMPlaneManager::UnsetUnusedPlanes(uint32_t crtc_id, drmModeAtomicReq *req) {
+ // Unset planes that were assigned to the crtc referred to by crtc_id but are not requested
+ // in this round
+ for (auto &plane : plane_pool_) {
+ uint32_t assigned_crtc = 0;
+ uint32_t requested_crtc = 0;
+ plane.second->GetAssignedCrtc(&assigned_crtc);
+ plane.second->GetRequestedCrtc(&requested_crtc);
+ if (assigned_crtc == crtc_id && requested_crtc == 0) {
+ plane.second->Unset(req);
+ }
+ }
+}
+
+void DRMPlaneManager::RetainPlanes(uint32_t crtc_id) {
+ for (auto &plane : plane_pool_) {
+ uint32_t assigned_crtc = 0;
+ plane.second->GetAssignedCrtc(&assigned_crtc);
+ if (assigned_crtc == crtc_id) {
+ // Pretend this plane was requested by client
+ plane.second->SetRequestedCrtc(crtc_id);
+ const uint32_t plane_id = plane.first;
+ DRM_LOGD("Plane %d: Retaining on CRTC %d", plane_id, crtc_id);
+ }
+ }
+}
+
+void DRMPlaneManager::PostValidate(uint32_t crtc_id, bool success) {
+ for (auto &plane : plane_pool_) {
+ plane.second->PostValidate(crtc_id, success);
+ }
+}
+
+void DRMPlaneManager::PostCommit(uint32_t crtc_id, bool success) {
+ DRM_LOGD("crtc %d", crtc_id);
+ for (auto &plane : plane_pool_) {
+ plane.second->PostCommit(crtc_id, success);
+ }
+}
+
+void DRMPlaneManager::SetScalerLUT(const DRMScalerLUTInfo &lut_info) {
+ if (lut_info.dir_lut_size) {
+ drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.dir_lut),
+ lut_info.dir_lut_size, &dir_lut_blob_id_);
+ }
+ if (lut_info.cir_lut_size) {
+ drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.cir_lut),
+ lut_info.cir_lut_size, &cir_lut_blob_id_);
+ }
+ if (lut_info.sep_lut_size) {
+ drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.sep_lut),
+ lut_info.sep_lut_size, &sep_lut_blob_id_);
+ }
+}
+
+void DRMPlaneManager::UnsetScalerLUT() {
+ if (dir_lut_blob_id_) {
+ drmModeDestroyPropertyBlob(fd_, dir_lut_blob_id_);
+ dir_lut_blob_id_ = 0;
+ }
+ if (cir_lut_blob_id_) {
+ drmModeDestroyPropertyBlob(fd_, cir_lut_blob_id_);
+ cir_lut_blob_id_ = 0;
+ }
+ if (sep_lut_blob_id_) {
+ drmModeDestroyPropertyBlob(fd_, sep_lut_blob_id_);
+ sep_lut_blob_id_ = 0;
+ }
+}
+
+// ==============================================================================================//
+
+#undef __CLASS__
+#define __CLASS__ "DRMPlane"
+
+DRMPlane::DRMPlane(int fd, uint32_t priority) : fd_(fd), priority_(priority) {}
+
+DRMPlane::~DRMPlane() {
+ drmModeFreePlane(drm_plane_);
+}
+
+void DRMPlane::GetTypeInfo(const PropertyMap &prop_map) {
+ uint64_t blob_id;
+ drmModePropertyRes *prop;
+ DRMPlaneTypeInfo *info = &plane_type_info_;
+ // Ideally we should check if this property type is a blob and then proceed.
+ std::tie(blob_id, prop) = prop_map.at(DRMProperty::CAPABILITIES);
+ drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
+ if (!blob) {
+ return;
+ }
+
+ const char *fmt_str = reinterpret_cast<const char *>(blob->data);
+ info->max_linewidth = 2560;
+ info->max_scaler_linewidth = 2560;
+ info->max_rotation_linewidth = 1088;
+ info->max_upscale = 1;
+ info->max_downscale = 1;
+ info->max_horizontal_deci = 0;
+ info->max_vertical_deci = 0;
+ info->master_plane_id = 0;
+ if (info->type == DRMPlaneType::CURSOR) {
+ info->max_linewidth = 128;
+ }
+ // TODO(user): change default to V2 once we start getting V3 via capabilities blob
+ info->qseed3_version = QSEEDStepVersion::V3;
+ info->has_excl_rect = has_excl_rect_;
+
+ // We may have multiple lines with each one dedicated for something specific
+ // like formats etc
+ stringstream stream(fmt_str);
+ string line = {};
+ string pixel_formats = "pixel_formats=";
+ string max_linewidth = "max_linewidth=";
+ string max_upscale = "max_upscale=";
+ string max_downscale = "max_downscale=";
+ string max_horizontal_deci = "max_horizontal_deci=";
+ string max_vertical_deci = "max_vertical_deci=";
+ string master_plane_id = "primary_smart_plane_id=";
+ string max_pipe_bw = "max_per_pipe_bw=";
+ string scaler_version = "scaler_step_ver=";
+ string block_sec_ui = "block_sec_ui=";
+ string true_inline_rot_rev = "true_inline_rot_rev=";
+ string inline_rot_pixel_formats = "inline_rot_pixel_formats=";
+
+ while (std::getline(stream, line)) {
+ if (line.find(inline_rot_pixel_formats) != string::npos) {
+ vector<pair<uint32_t, uint64_t>> inrot_formats_supported;
+ ParseFormats(line.erase(0, inline_rot_pixel_formats.length()), &inrot_formats_supported);
+ info->inrot_fmts_supported = std::move(inrot_formats_supported);
+ } else if (line.find(pixel_formats) != string::npos) {
+ vector<pair<uint32_t, uint64_t>> formats_supported;
+ ParseFormats(line.erase(0, pixel_formats.length()), &formats_supported);
+ info->formats_supported = std::move(formats_supported);
+ } else if (line.find(max_linewidth) != string::npos) {
+ info->max_linewidth = std::stoi(line.erase(0, max_linewidth.length()));
+ } else if (line.find(max_upscale) != string::npos) {
+ info->max_upscale = std::stoi(line.erase(0, max_upscale.length()));
+ } else if (line.find(max_downscale) != string::npos) {
+ info->max_downscale = std::stoi(line.erase(0, max_downscale.length()));
+ } else if (line.find(max_horizontal_deci) != string::npos) {
+ info->max_horizontal_deci = std::stoi(line.erase(0, max_horizontal_deci.length()));
+ } else if (line.find(max_vertical_deci) != string::npos) {
+ info->max_vertical_deci = std::stoi(line.erase(0, max_vertical_deci.length()));
+ } else if (line.find(master_plane_id) != string::npos) {
+ info->master_plane_id = std::stoi(line.erase(0, master_plane_id.length()));
+ DRM_LOGI("info->master_plane_id: detected master_plane=%d", info->master_plane_id);
+ } else if (line.find(max_pipe_bw) != string::npos) {
+ info->max_pipe_bandwidth = std::stoull(line.erase(0, max_pipe_bw.length()));
+ } else if (line.find(scaler_version) != string::npos) {
+ info->qseed3_version =
+ PopulateQseedStepVersion(std::stoi(line.erase(0, scaler_version.length())));
+ } else if (line.find(block_sec_ui) != string::npos) {
+ info->block_sec_ui = !!(std::stoi(line.erase(0, block_sec_ui.length())));
+ } else if (line.find(true_inline_rot_rev) != string::npos) {
+ info->inrot_version =
+ PopulateInlineRotationVersion(std::stoi(line.erase(0, true_inline_rot_rev.length())));
+ }
+ }
+
+ info->max_scaler_linewidth = (QSEEDStepVersion::V4 == info->qseed3_version) ? 2560 :
+ info->max_linewidth;
+ drmModeFreePropertyBlob(blob);
+}
+
+void DRMPlane::ParseProperties() {
+ // Map of property name to current value and property info pointer
+ PropertyMap prop_map;
+ bool csc = false;
+ bool scaler = false;
+ bool cursor = false;
+ drmModeObjectProperties *props =
+ drmModeObjectGetProperties(fd_, drm_plane_->plane_id, DRM_MODE_OBJECT_PLANE);
+ if (!props || !props->props || !props->prop_values) {
+ drmModeFreeObjectProperties(props);
+ return;
+ }
+
+ for (uint32_t j = 0; j < props->count_props; j++) {
+ drmModePropertyRes *info = drmModeGetProperty(fd_, props->props[j]);
+ if (!info) {
+ continue;
+ }
+
+ string property_name(info->name);
+ DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name);
+ if (prop_enum == DRMProperty::INVALID) {
+ DRM_LOGD("DRMProperty %s missing from global property mapping", info->name);
+ drmModeFreeProperty(info);
+ continue;
+ }
+
+ if (prop_enum == DRMProperty::EXCL_RECT) {
+ has_excl_rect_ = true;
+ }
+ if (prop_enum == DRMProperty::ROTATION) {
+ PopulateReflect(info);
+ } else if (prop_enum == DRMProperty::FB_TRANSLATION_MODE) {
+ PopulateSecureModes(info);
+ } else if (prop_enum == DRMProperty::MULTIRECT_MODE) {
+ PopulateMultiRectModes(info);
+ plane_type_info_.multirect_prop_present = true;
+ }
+
+ prop_mgr_.SetPropertyId(prop_enum, info->prop_id);
+ prop_map[prop_enum] = std::make_tuple(props->prop_values[j], info);
+ csc = prop_enum == DRMProperty::CSC_V1 ? true : csc;
+ scaler = (prop_enum == DRMProperty::SCALER_V1 || prop_enum == DRMProperty::SCALER_V2) \
+ ? true : scaler;
+ cursor = (prop_enum == DRMProperty::TYPE && props->prop_values[j] == DRM_PLANE_TYPE_CURSOR) \
+ ? true : cursor;
+
+ // Tone mapping properties.
+ if (prop_enum == DRMProperty::INVERSE_PMA) {
+ plane_type_info_.inverse_pma = true;
+ }
+
+ if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::CSC_DMA_V1 &&
+ (uint32_t)prop_enum <= (uint32_t)DRMProperty::CSC_DMA_V1) {
+ plane_type_info_.dgm_csc_version =
+ ((uint32_t)prop_enum - (uint32_t)DRMProperty::CSC_DMA_V1 + 1);
+ }
+
+ if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5 &&
+ (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5) {
+ plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::DMA_1D_IGC] =
+ ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5 + 5);
+ }
+ if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5 &&
+ (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5) {
+ plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::DMA_1D_GC] =
+ ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5 + 5);
+ }
+ if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V5 &&
+ (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V5) {
+ plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::VIG_1D_IGC] =
+ ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V5 + 5);
+ }
+ if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5 &&
+ (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5) {
+ plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::VIG_3D_GAMUT] =
+ ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5 + 5);
+ }
+ }
+
+ DRMPlaneType type = DRMPlaneType::DMA;
+ if (csc && scaler) {
+ type = DRMPlaneType::VIG;
+ } else if (cursor) {
+ type = DRMPlaneType::CURSOR;
+ }
+
+ plane_type_info_.type = type;
+ GetTypeInfo(prop_map);
+
+ for (auto &prop : prop_map) {
+ drmModeFreeProperty(std::get<1>(prop.second));
+ }
+
+ drmModeFreeObjectProperties(props);
+}
+
+void DRMPlane::InitAndParse(drmModePlane *plane) {
+ drm_plane_ = plane;
+ ParseProperties();
+
+ unique_ptr<DRMPPManager> pp_mgr(new DRMPPManager(fd_));
+ pp_mgr_ = std::move(pp_mgr);
+ pp_mgr_->Init(prop_mgr_, DRM_MODE_OBJECT_PLANE);
+}
+
+bool DRMPlane::ConfigureScalerLUT(drmModeAtomicReq *req, uint32_t dir_lut_blob_id,
+ uint32_t cir_lut_blob_id, uint32_t sep_lut_blob_id) {
+ if (plane_type_info_.type != DRMPlaneType::VIG || is_lut_configured_) {
+ return false;
+ }
+
+ if (dir_lut_blob_id) {
+ AddProperty(req, drm_plane_->plane_id,
+ prop_mgr_.GetPropertyId(DRMProperty::LUT_ED),
+ dir_lut_blob_id, false /* cache */, tmp_prop_val_map_);
+ }
+ if (cir_lut_blob_id) {
+ AddProperty(req, drm_plane_->plane_id,
+ prop_mgr_.GetPropertyId(DRMProperty::LUT_CIR),
+ cir_lut_blob_id, false /* cache */, tmp_prop_val_map_);
+ }
+ if (sep_lut_blob_id) {
+ AddProperty(req, drm_plane_->plane_id,
+ prop_mgr_.GetPropertyId(DRMProperty::LUT_SEP),
+ sep_lut_blob_id, false /* cache */, tmp_prop_val_map_);
+ }
+
+ return true;
+}
+
+void DRMPlane::SetExclRect(drmModeAtomicReq *req, DRMRect rect) {
+ auto prop_id = prop_mgr_.GetPropertyId(DRMProperty::EXCL_RECT);
+ drm_clip_rect clip_rect;
+ SetRect(rect, &clip_rect);
+ excl_rect_copy_ = clip_rect;
+ AddProperty(req, drm_plane_->plane_id, prop_id, reinterpret_cast<uint64_t>
+ (&excl_rect_copy_), false /* cache */, tmp_prop_val_map_);
+ DRM_LOGD("Plane %d: Setting exclusion rect [x,y,w,h][%d,%d,%d,%d]", drm_plane_->plane_id,
+ clip_rect.x1, clip_rect.y1, (clip_rect.x2 - clip_rect.x1),
+ (clip_rect.y2 - clip_rect.y1));
+}
+
+bool DRMPlane::SetCscConfig(drmModeAtomicReq *req, DRMCscType csc_type) {
+ if (plane_type_info_.type != DRMPlaneType::VIG) {
+ return false;
+ }
+
+ if (csc_type > kCscTypeMax) {
+ return false;
+ }
+
+ if (!prop_mgr_.IsPropertyAvailable(DRMProperty::CSC_V1)) {
+ return false;
+ }
+
+ auto prop_id = prop_mgr_.GetPropertyId(DRMProperty::CSC_V1);
+ if (csc_type == kCscTypeMax) {
+ AddProperty(req, drm_plane_->plane_id, prop_id, 0, false /* cache */, tmp_prop_val_map_);
+ } else {
+ csc_config_copy_ = csc_10bit_convert[csc_type];
+ AddProperty(req, drm_plane_->plane_id, prop_id,
+ reinterpret_cast<uint64_t>(&csc_config_copy_), false /* cache */,
+ tmp_prop_val_map_);
+ }
+
+ return true;
+}
+
+bool DRMPlane::SetScalerConfig(drmModeAtomicReq *req, uint64_t handle) {
+ if (plane_type_info_.type != DRMPlaneType::VIG) {
+ return false;
+ }
+
+ if (prop_mgr_.IsPropertyAvailable(DRMProperty::SCALER_V2)) {
+ auto prop_id = prop_mgr_.GetPropertyId(DRMProperty::SCALER_V2);
+ sde_drm_scaler_v2 *scaler_v2_config = reinterpret_cast<sde_drm_scaler_v2 *>(handle);
+ uint64_t scaler_data = 0;
+ // The address needs to be valid even after async commit, since we are sending address to
+ // driver directly, instead of blob. So we need to copy over contents that client sent. Client
+ // may have sent an address of object on stack which will be released after this call.
+ scaler_v2_config_copy_ = *scaler_v2_config;
+ if (scaler_v2_config_copy_.enable) {
+ scaler_data = reinterpret_cast<uint64_t>(&scaler_v2_config_copy_);
+ }
+ AddProperty(req, drm_plane_->plane_id, prop_id, scaler_data, false /* cache */,
+ tmp_prop_val_map_);
+ return true;
+ }
+
+ return false;
+}
+
+void DRMPlane::SetDecimation(drmModeAtomicReq *req, uint32_t prop_id, uint32_t prop_value) {
+ if (plane_type_info_.type == DRMPlaneType::DMA || plane_type_info_.master_plane_id) {
+ // if value is 0, client is just trying to clear previous decimation, so bail out silently
+ if (prop_value > 0) {
+ DRM_LOGE("Plane %d: Setting decimation %d is not supported.", drm_plane_->plane_id,
+ prop_value);
+ }
+ return;
+ }
+
+ // TODO(user): Currently a ViG plane in smart DMA mode could receive a non-zero decimation value
+ // but there is no good way to catch. In any case fix will be in client
+ AddProperty(req, drm_plane_->plane_id, prop_id, prop_value, true /* cache */, tmp_prop_val_map_);
+ DRM_LOGD("Plane %d: Setting decimation %d", drm_plane_->plane_id, prop_value);
+}
+
+void DRMPlane::PostValidate(uint32_t crtc_id, bool /*success*/) {
+ if (requested_crtc_id_ == crtc_id) {
+ SetRequestedCrtc(0);
+ tmp_prop_val_map_ = committed_prop_val_map_;
+ }
+}
+
+void DRMPlane::PostCommit(uint32_t crtc_id, bool success) {
+ DRM_LOGD("crtc %d", crtc_id);
+ if (!success) {
+ // To reset
+ PostValidate(crtc_id, success);
+ return;
+ }
+
+ uint32_t assigned_crtc = 0;
+ uint32_t requested_crtc = 0;
+
+ GetAssignedCrtc(&assigned_crtc);
+ GetRequestedCrtc(&requested_crtc);
+
+ // In future, it is possible that plane is already attached in case of continuous splash. This
+ // will cause the first commit to only unstage pipes. We want to mark luts as configured only
+ // when they really are, which typically happens if a crtc is requested for a plane
+ if (requested_crtc == crtc_id && !is_lut_configured_) {
+ is_lut_configured_ = true;
+ }
+
+ if (requested_crtc && assigned_crtc && requested_crtc != assigned_crtc) {
+ // We should never be here
+ DRM_LOGE("Found plane %d switching from crtc %d to crtc %d", drm_plane_->plane_id,
+ assigned_crtc, requested_crtc);
+ }
+
+ // If we have set a pipe OR unset a pipe during commit, update states
+ if (requested_crtc == crtc_id || assigned_crtc == crtc_id) {
+ committed_prop_val_map_ = tmp_prop_val_map_;
+ SetAssignedCrtc(requested_crtc);
+ SetRequestedCrtc(0);
+ }
+}
+
+void DRMPlane::Perform(DRMOps code, drmModeAtomicReq *req, va_list args) {
+ uint32_t prop_id = 0;
+ uint32_t obj_id = drm_plane_->plane_id;
+
+ switch (code) {
+ // TODO(user): Check if these exist in map before attempting to access
+ case DRMOps::PLANE_SET_SRC_RECT: {
+ DRMRect rect = va_arg(args, DRMRect);
+ // source co-ordinates accepted by DRM are 16.16 fixed point
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::SRC_X);
+ AddProperty(req, obj_id, prop_id, rect.left << 16, true /* cache */, tmp_prop_val_map_);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::SRC_Y);
+ AddProperty(req, obj_id, prop_id, rect.top << 16, true /* cache */, tmp_prop_val_map_);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::SRC_W);
+ AddProperty(req, obj_id, prop_id, (rect.right - rect.left) << 16, true /* cache */,
+ tmp_prop_val_map_);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::SRC_H);
+ AddProperty(req, obj_id, prop_id, (rect.bottom - rect.top) << 16, true /* cache */,
+ tmp_prop_val_map_);
+ DRM_LOGV("Plane %d: Setting crop [x,y,w,h][%d,%d,%d,%d]", obj_id, rect.left,
+ rect.top, (rect.right - rect.left), (rect.bottom - rect.top));
+ } break;
+
+ case DRMOps::PLANE_SET_DST_RECT: {
+ DRMRect rect = va_arg(args, DRMRect);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::CRTC_X);
+ AddProperty(req, obj_id, prop_id, rect.left, true /* cache */, tmp_prop_val_map_);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::CRTC_Y);
+ AddProperty(req, obj_id, prop_id, rect.top, true /* cache */, tmp_prop_val_map_);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::CRTC_W);
+ AddProperty(req, obj_id, prop_id, (rect.right - rect.left), true /* cache */,
+ tmp_prop_val_map_);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::CRTC_H);
+ AddProperty(req, obj_id, prop_id, (rect.bottom - rect.top), true /* cache */,
+ tmp_prop_val_map_);
+ DRM_LOGV("Plane %d: Setting dst [x,y,w,h][%d,%d,%d,%d]", obj_id, rect.left,
+ rect.top, (rect.right - rect.left), (rect.bottom - rect.top));
+ } break;
+ case DRMOps::PLANE_SET_EXCL_RECT: {
+ DRMRect excl_rect = va_arg(args, DRMRect);
+ SetExclRect(req, excl_rect);
+ } break;
+
+ case DRMOps::PLANE_SET_ZORDER: {
+ uint32_t zpos = va_arg(args, uint32_t);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::ZPOS);
+ AddProperty(req, obj_id, prop_id, zpos, true /* cache */, tmp_prop_val_map_);
+ DRM_LOGD("Plane %d: Setting z %d", obj_id, zpos);
+ } break;
+
+ case DRMOps::PLANE_SET_ROTATION: {
+ uint32_t rot_bit_mask = va_arg(args, uint32_t);
+ uint32_t drm_rot_bit_mask = 0;
+ if (rot_bit_mask & static_cast<uint32_t>(DRMRotation::FLIP_H)) {
+ drm_rot_bit_mask |= 1 << REFLECT_X;
+ }
+ if (rot_bit_mask & static_cast<uint32_t>(DRMRotation::FLIP_V)) {
+ drm_rot_bit_mask |= 1 << REFLECT_Y;
+ }
+ if (rot_bit_mask & static_cast<uint32_t>(DRMRotation::ROT_90)) {
+ drm_rot_bit_mask |= 1 << ROTATE_90;
+ } else {
+ drm_rot_bit_mask |= 1 << ROTATE_0;
+ }
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::ROTATION);
+ AddProperty(req, obj_id, prop_id, drm_rot_bit_mask, true /* cache */, tmp_prop_val_map_);
+ DRM_LOGV("Plane %d: Setting rotation mask %x", obj_id, drm_rot_bit_mask);
+ } break;
+
+ case DRMOps::PLANE_SET_ALPHA: {
+ uint32_t alpha = va_arg(args, uint32_t);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::ALPHA);
+ AddProperty(req, obj_id, prop_id, alpha, true /* cache */, tmp_prop_val_map_);
+ DRM_LOGV("Plane %d: Setting alpha %d", obj_id, alpha);
+ } break;
+
+ case DRMOps::PLANE_SET_BLEND_TYPE: {
+ uint32_t blending = va_arg(args, uint32_t);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::BLEND_OP);
+ AddProperty(req, obj_id, prop_id, blending, true /* cache */, tmp_prop_val_map_);
+ DRM_LOGV("Plane %d: Setting blending %d", obj_id, blending);
+ } break;
+
+ case DRMOps::PLANE_SET_H_DECIMATION: {
+ uint32_t deci = va_arg(args, uint32_t);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::H_DECIMATE);
+ SetDecimation(req, prop_id, deci);
+ } break;
+
+ case DRMOps::PLANE_SET_V_DECIMATION: {
+ uint32_t deci = va_arg(args, uint32_t);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::V_DECIMATE);
+ SetDecimation(req, prop_id, deci);
+ } break;
+
+ case DRMOps::PLANE_SET_SRC_CONFIG: {
+ bool src_config = va_arg(args, uint32_t);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::SRC_CONFIG);
+ AddProperty(req, obj_id, prop_id, src_config, true /* cache */, tmp_prop_val_map_);
+ DRM_LOGV("Plane %d: Setting src_config flags-%x", obj_id, src_config);
+ } break;
+
+ case DRMOps::PLANE_SET_CRTC: {
+ uint32_t crtc_id = va_arg(args, uint32_t);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::CRTC_ID);
+ AddProperty(req, obj_id, prop_id, crtc_id, true /* cache */, tmp_prop_val_map_);
+ SetRequestedCrtc(crtc_id);
+ DRM_LOGV("Plane %d: Setting crtc %d", obj_id, crtc_id);
+ } break;
+
+ case DRMOps::PLANE_SET_FB_ID: {
+ uint32_t fb_id = va_arg(args, uint32_t);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::FB_ID);
+ AddProperty(req, obj_id, prop_id, fb_id, true /* cache */, tmp_prop_val_map_);
+ DRM_LOGV("Plane %d: Setting fb_id %d", obj_id, fb_id);
+ } break;
+
+ case DRMOps::PLANE_SET_ROT_FB_ID: {
+ uint32_t fb_id = va_arg(args, uint32_t);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::ROT_FB_ID);
+ drmModeAtomicAddProperty(req, obj_id, prop_id, fb_id);
+ DRM_LOGV("Plane %d: Setting rot_fb_id %d", obj_id, fb_id);
+ } break;
+
+ case DRMOps::PLANE_SET_INPUT_FENCE: {
+ int fence = va_arg(args, int);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::INPUT_FENCE);
+ AddProperty(req, obj_id, prop_id, fence, false /* cache */, tmp_prop_val_map_);
+ DRM_LOGV("Plane %d: Setting input fence %d", obj_id, fence);
+ } break;
+
+ case DRMOps::PLANE_SET_SCALER_CONFIG: {
+ uint64_t handle = va_arg(args, uint64_t);
+ if (SetScalerConfig(req, handle)) {
+ DRM_LOGV("Plane %d: Setting scaler config", obj_id);
+ }
+ } break;
+
+ case DRMOps::PLANE_SET_FB_SECURE_MODE: {
+ int secure_mode = va_arg(args, int);
+ uint32_t fb_secure_mode = NON_SECURE;
+ switch (secure_mode) {
+ case (int)DRMSecureMode::NON_SECURE:
+ fb_secure_mode = NON_SECURE;
+ break;
+ case (int)DRMSecureMode::SECURE:
+ fb_secure_mode = SECURE;
+ break;
+ case (int)DRMSecureMode::NON_SECURE_DIR_TRANSLATION:
+ fb_secure_mode = NON_SECURE_DIR_TRANSLATION;
+ break;
+ case (int)DRMSecureMode::SECURE_DIR_TRANSLATION:
+ fb_secure_mode = SECURE_DIR_TRANSLATION;
+ break;
+ default:
+ DRM_LOGE("Invalid secure mode %d to set on plane %d", secure_mode, obj_id);
+ break;
+ }
+
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::FB_TRANSLATION_MODE);
+ AddProperty(req, obj_id, prop_id, fb_secure_mode, true /* cache */, tmp_prop_val_map_);
+ DRM_LOGD("Plane %d: Setting FB secure mode %d", obj_id, fb_secure_mode);
+ } break;
+
+ case DRMOps::PLANE_SET_CSC_CONFIG: {
+ uint32_t* csc_type = va_arg(args, uint32_t*);
+ if (csc_type) {
+ SetCscConfig(req, (DRMCscType)*csc_type);
+ }
+ } break;
+
+ case DRMOps::PLANE_SET_MULTIRECT_MODE: {
+ DRMMultiRectMode drm_multirect_mode = (DRMMultiRectMode)va_arg(args, uint32_t);
+ SetMultiRectMode(req, drm_multirect_mode);
+ } break;
+
+ case DRMOps::PLANE_SET_INVERSE_PMA: {
+ uint32_t pma = va_arg(args, uint32_t);
+ prop_id = prop_mgr_.GetPropertyId(DRMProperty::INVERSE_PMA);
+ AddProperty(req, obj_id, prop_id, pma, true /* cache */, tmp_prop_val_map_);
+ DRM_LOGD("Plane %d: %s inverse pma", obj_id, pma ? "Setting" : "Resetting");
+ } break;
+
+ case DRMOps::PLANE_SET_DGM_CSC_CONFIG: {
+ uint64_t handle = va_arg(args, uint64_t);
+ if (SetDgmCscConfig(req, handle)) {
+ DRM_LOGD("Plane %d: Setting Csc Lut config", obj_id);
+ }
+ } break;
+
+ case DRMOps::PLANE_SET_POST_PROC: {
+ DRMPPFeatureInfo *data = va_arg(args, DRMPPFeatureInfo*);
+ if (data) {
+ DRM_LOGD("Plane %d: Set post proc", obj_id);
+ pp_mgr_->SetPPFeature(req, obj_id, *data);
+ }
+ } break;
+
+ default:
+ DRM_LOGE("Invalid opcode %d for DRM Plane %d", code, obj_id);
+ }
+}
+
+void DRMPlane::PerformWrapper(DRMOps code, drmModeAtomicReq *req, ...) {
+ va_list args;
+ va_start(args, req);
+ Perform(code, req, args);
+ va_end(args);
+}
+
+void DRMPlane::Dump() {
+ DRM_LOGE(
+ "id: %d\tcrtc id: %d\tfb id: %d\tCRTC_xy: %dx%d\txy: %dx%d\tgamma "
+ "size: %d\tpossible crtc: 0x%x\n",
+ drm_plane_->plane_id, drm_plane_->crtc_id, drm_plane_->fb_id, drm_plane_->crtc_x,
+ drm_plane_->crtc_y, drm_plane_->x, drm_plane_->y, drm_plane_->gamma_size,
+ drm_plane_->possible_crtcs);
+ DRM_LOGE("Format Suported: \n");
+ for (uint32_t i = 0; i < (uint32_t)drm_plane_->count_formats; i++)
+ DRM_LOGE(" %4.4s", (char *)&drm_plane_->formats[i]);
+}
+
+void DRMPlane::SetMultiRectMode(drmModeAtomicReq *req, DRMMultiRectMode drm_multirect_mode) {
+ if (!plane_type_info_.multirect_prop_present) {
+ return;
+ }
+ uint32_t obj_id = drm_plane_->plane_id;
+ uint32_t multirect_mode = MULTIRECT_NONE;
+ switch (drm_multirect_mode) {
+ case DRMMultiRectMode::NONE:
+ multirect_mode = MULTIRECT_NONE;
+ break;
+ case DRMMultiRectMode::PARALLEL:
+ multirect_mode = MULTIRECT_PARALLEL;
+ break;
+ case DRMMultiRectMode::SERIAL:
+ multirect_mode = MULTIRECT_SERIAL;
+ break;
+ default:
+ DRM_LOGE("Invalid multirect mode %d to set on plane %d", drm_multirect_mode, obj_id);
+ break;
+ }
+ auto prop_id = prop_mgr_.GetPropertyId(DRMProperty::MULTIRECT_MODE);
+ AddProperty(req, obj_id, prop_id, multirect_mode, true /* cache */, tmp_prop_val_map_);
+ DRM_LOGD("Plane %d: Setting multirect_mode %d", obj_id, multirect_mode);
+}
+
+void DRMPlane::Unset(drmModeAtomicReq *req) {
+ DRM_LOGD("Plane %d: Unsetting from crtc %d", drm_plane_->plane_id, assigned_crtc_id_);
+ PerformWrapper(DRMOps::PLANE_SET_FB_ID, req, 0);
+ PerformWrapper(DRMOps::PLANE_SET_CRTC, req, 0);
+ DRMRect rect = {0, 0, 0, 0};
+ PerformWrapper(DRMOps::PLANE_SET_SRC_RECT, req, rect);
+ PerformWrapper(DRMOps::PLANE_SET_DST_RECT, req, rect);
+ PerformWrapper(DRMOps::PLANE_SET_EXCL_RECT, req, rect);
+ if (plane_type_info_.inverse_pma) {
+ PerformWrapper(DRMOps::PLANE_SET_INVERSE_PMA, req, 0);
+ }
+ tmp_prop_val_map_.clear();
+ committed_prop_val_map_.clear();
+}
+
+bool DRMPlane::SetDgmCscConfig(drmModeAtomicReq *req, uint64_t handle) {
+ if (plane_type_info_.type == DRMPlaneType::DMA &&
+ prop_mgr_.IsPropertyAvailable(DRMProperty::CSC_DMA_V1)) {
+ auto prop_id = prop_mgr_.GetPropertyId(DRMProperty::CSC_DMA_V1);
+ sde_drm_csc_v1 *csc_v1 = reinterpret_cast<sde_drm_csc_v1 *>(handle);
+ uint64_t csc_v1_data = 0;
+ sde_drm_csc_v1 csc_v1_tmp = {};
+ csc_config_copy_ = *csc_v1;
+ if (std::memcmp(&csc_config_copy_, &csc_v1_tmp, sizeof(sde_drm_csc_v1)) != 0) {
+ csc_v1_data = reinterpret_cast<uint64_t>(&csc_config_copy_);
+ }
+ DRM_LOGV("Dgm CSC = %d", csc_v1_data);
+ AddProperty(req, drm_plane_->plane_id, prop_id,
+ reinterpret_cast<uint64_t>(csc_v1_data), false /* cache */,
+ tmp_prop_val_map_);
+
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace sde_drm