diff options
author | Roman Stratiienko <r.stratiienko@gmail.com> | 2023-01-17 18:06:04 +0200 |
---|---|---|
committer | Roman Stratiienko <r.stratiienko@gmail.com> | 2023-01-18 17:20:01 +0200 |
commit | 0da91bf5bb72323a0f0d1928a1fc36a01c1b7941 (patch) | |
tree | c9c41c3efc5aa707acc0a23d4108ce69cd2fa3c6 | |
parent | 359a9d397100cf531f203ded61d2578957fb526f (diff) | |
download | drm_hwcomposer-0da91bf5bb72323a0f0d1928a1fc36a01c1b7941.tar.gz |
drm_hwcomposer: Add support for color transform matrix
1. Add and wire-up CRTC CTM property support.
2. Add custom Android property to select behavior for cases
where DRM can't handle color transform matrix.
The "vendor.hwc.drm.ctm" property can be set to:
- DRM_OR_GPU (default) - Use GPU if CTM is not supported by DRM.
- DRM_OR_IGNORE - Ignore CTM if DRM doesn't support it.
The last option is useful for Android 13 and later where default
color transformation matrix is not an identity matrix.
At the moment I do not have any devices with CTM support, therefore
I can test only DRM_OR_IGNORE option.
Signed-off-by: Roman Stratiienko <r.stratiienko@gmail.com>
-rw-r--r-- | backend/Backend.cpp | 3 | ||||
-rw-r--r-- | drm/DrmAtomicStateManager.cpp | 14 | ||||
-rw-r--r-- | drm/DrmAtomicStateManager.h | 2 | ||||
-rw-r--r-- | drm/DrmCrtc.cpp | 5 | ||||
-rw-r--r-- | drm/DrmCrtc.h | 6 | ||||
-rw-r--r-- | drm/ResourceManager.cpp | 18 | ||||
-rw-r--r-- | drm/ResourceManager.h | 11 | ||||
-rw-r--r-- | hwc2_device/HwcDisplay.cpp | 93 | ||||
-rw-r--r-- | hwc2_device/HwcDisplay.h | 14 |
9 files changed, 139 insertions, 27 deletions
diff --git a/backend/Backend.cpp b/backend/Backend.cpp index 679f083..f3156ed 100644 --- a/backend/Backend.cpp +++ b/backend/Backend.cpp @@ -83,8 +83,7 @@ std::tuple<int, size_t> Backend::GetClientLayers( bool Backend::IsClientLayer(HwcDisplay *display, HwcLayer *layer) { return !HardwareSupportsLayerType(layer->GetSfType()) || - !layer->IsLayerUsableAsDevice() || - display->color_transform_hint() != HAL_COLOR_TRANSFORM_IDENTITY || + !layer->IsLayerUsableAsDevice() || display->CtmByGpu() || (layer->GetLayerData().pi.RequireScalingOrPhasing() && display->GetHwc2()->GetResMan().ForcedScalingWithGpu()); } diff --git a/drm/DrmAtomicStateManager.cpp b/drm/DrmAtomicStateManager.cpp index 58a5523..4ff16e2 100644 --- a/drm/DrmAtomicStateManager.cpp +++ b/drm/DrmAtomicStateManager.cpp @@ -107,6 +107,20 @@ auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int { } } + if (args.color_matrix && crtc->GetCtmProperty()) { + auto blob = drm->RegisterUserPropertyBlob(args.color_matrix.get(), + sizeof(drm_color_ctm)); + new_frame_state.ctm_blob = std::move(blob); + + if (!new_frame_state.ctm_blob) { + ALOGE("Failed to create CTM blob"); + return -EINVAL; + } + + if (!crtc->GetCtmProperty().AtomicSet(*pset, *new_frame_state.ctm_blob)) + return -EINVAL; + } + auto unused_planes = new_frame_state.used_planes; if (args.composition) { diff --git a/drm/DrmAtomicStateManager.h b/drm/DrmAtomicStateManager.h index e456a91..6e32a37 100644 --- a/drm/DrmAtomicStateManager.h +++ b/drm/DrmAtomicStateManager.h @@ -35,6 +35,7 @@ struct AtomicCommitArgs { std::optional<DrmMode> display_mode; std::optional<bool> active; std::shared_ptr<DrmKmsPlan> composition; + std::shared_ptr<drm_color_ctm> color_matrix; /* out */ SharedFd out_fence; @@ -75,6 +76,7 @@ class DrmAtomicStateManager { std::vector<std::shared_ptr<DrmFbIdHandle>> used_framebuffers; DrmModeUserPropertyBlobUnique mode_blob; + DrmModeUserPropertyBlobUnique ctm_blob; int release_fence_pt_index{}; diff --git a/drm/DrmCrtc.cpp b/drm/DrmCrtc.cpp index 3b749b1..948a9ac 100644 --- a/drm/DrmCrtc.cpp +++ b/drm/DrmCrtc.cpp @@ -61,6 +61,11 @@ auto DrmCrtc::CreateInstance(DrmDevice &dev, uint32_t crtc_id, uint32_t index) return {}; } + ret = GetCrtcProperty(dev, *c, "CTM", &c->ctm_property_); + if (ret != 0) { + ALOGV("Missing optional CTM property"); + } + return c; } diff --git a/drm/DrmCrtc.h b/drm/DrmCrtc.h index 64fb56f..96443cd 100644 --- a/drm/DrmCrtc.h +++ b/drm/DrmCrtc.h @@ -58,6 +58,10 @@ class DrmCrtc : public PipelineBindable<DrmCrtc> { return out_fence_ptr_property_; } + auto &GetCtmProperty() const { + return ctm_property_; + } + private: DrmCrtc(DrmModeCrtcUnique crtc, uint32_t index) : crtc_(std::move(crtc)), index_in_res_array_(index){}; @@ -66,6 +70,8 @@ class DrmCrtc : public PipelineBindable<DrmCrtc> { const uint32_t index_in_res_array_; + DrmProperty ctm_property_; + DrmProperty active_property_; DrmProperty mode_property_; DrmProperty out_fence_ptr_property_; diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp index dd26c17..577d86c 100644 --- a/drm/ResourceManager.cpp +++ b/drm/ResourceManager.cpp @@ -72,9 +72,21 @@ void ResourceManager::Init() { } } - char scale_with_gpu[PROPERTY_VALUE_MAX]; - property_get("vendor.hwc.drm.scale_with_gpu", scale_with_gpu, "0"); - scale_with_gpu_ = bool(strncmp(scale_with_gpu, "0", 1)); + char proptext[PROPERTY_VALUE_MAX]; + property_get("vendor.hwc.drm.scale_with_gpu", proptext, "0"); + scale_with_gpu_ = bool(strncmp(proptext, "0", 1)); + + constexpr char kDrmOrGpu[] = "DRM_OR_GPU"; + constexpr char kDrmOrIgnore[] = "DRM_OR_IGNORE"; + property_get("vendor.hwc.drm.ctm", proptext, kDrmOrGpu); + if (strncmp(proptext, kDrmOrGpu, sizeof(kDrmOrGpu)) == 0) { + ctm_handling_ = CtmHandling::kDrmOrGpu; + } else if (strncmp(proptext, kDrmOrIgnore, sizeof(kDrmOrIgnore)) == 0) { + ctm_handling_ = CtmHandling::kDrmOrIgnore; + } else { + ALOGE("Invalid value for vendor.hwc.drm.ctm: %s", proptext); + ctm_handling_ = CtmHandling::kDrmOrGpu; + } if (BufferInfoGetter::GetInstance() == nullptr) { ALOGE("Failed to initialize BufferInfoGetter"); diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h index 60b6b16..7fa3fc6 100644 --- a/drm/ResourceManager.h +++ b/drm/ResourceManager.h @@ -26,6 +26,11 @@ namespace android { +enum class CtmHandling { + kDrmOrGpu, /* Handled by DRM is possible, otherwise by GPU */ + kDrmOrIgnore, /* Handled by DRM is possible, otherwise displayed as is */ +}; + class PipelineToFrontendBindingInterface { public: virtual ~PipelineToFrontendBindingInterface() = default; @@ -52,6 +57,10 @@ class ResourceManager { return scale_with_gpu_; } + auto &GetCtmHandling() const { + return ctm_handling_; + } + auto &GetMainLock() { return main_lock_; } @@ -65,7 +74,9 @@ class ResourceManager { std::vector<std::unique_ptr<DrmDevice>> drms_; + // Android properties: bool scale_with_gpu_{}; + CtmHandling ctm_handling_{}; std::shared_ptr<UEventListener> uevent_listener_; diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp index 1550e21..cdcf518 100644 --- a/hwc2_device/HwcDisplay.cpp +++ b/hwc2_device/HwcDisplay.cpp @@ -87,17 +87,18 @@ std::string HwcDisplay::Dump() { HwcDisplay::HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type, DrmHwcTwo *hwc2) - : hwc2_(hwc2), - handle_(handle), - type_(type), - client_layer_(this), - color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) { - // clang-format off - color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0}; - // clang-format on + : hwc2_(hwc2), handle_(handle), type_(type), client_layer_(this){}; + +void HwcDisplay::SetColorMarixToIdentity() { + color_matrix_ = std::make_shared<drm_color_ctm>(); + for (int i = 0; i < kCtmCols; i++) { + for (int j = 0; j < kCtmRows; j++) { + constexpr uint64_t kOne = 1L << 32; /* 1.0 in s31.32 format */ + color_matrix_->matrix[i * kCtmRows + j] = (i == j) ? kOne : 0; + } + } + + color_transform_hint_ = HAL_COLOR_TRANSFORM_IDENTITY; } HwcDisplay::~HwcDisplay() = default; @@ -195,6 +196,8 @@ HWC2::Error HwcDisplay::Init() { client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED); + SetColorMarixToIdentity(); + return HWC2::Error::None; } @@ -465,6 +468,8 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) { return HWC2::Error::None; } + a_args.color_matrix = color_matrix_; + uint32_t prev_vperiod_ns = 0; GetDisplayVsyncPeriod(&prev_vperiod_ns); @@ -595,6 +600,9 @@ HWC2::Error HwcDisplay::PresentDisplay(int32_t *out_present_fence) { this->present_fence_ = a_args.out_fence; *out_present_fence = DupFd(a_args.out_fence); + // Reset the color matrix so we don't apply it over and over again. + color_matrix_ = {}; + ++frame_no_; return HWC2::Error::None; } @@ -673,6 +681,8 @@ HWC2::Error HwcDisplay::SetColorMode(int32_t mode) { return HWC2::Error::None; } +#include <xf86drmMode.h> + HWC2::Error HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) { if (hint < HAL_COLOR_TRANSFORM_IDENTITY || hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA) @@ -682,12 +692,46 @@ HWC2::Error HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) { return HWC2::Error::BadParameter; color_transform_hint_ = static_cast<android_color_transform_t>(hint); - if (color_transform_hint_ == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) - std::copy(matrix, matrix + MATRIX_SIZE, color_transform_matrix_.begin()); + + if (!GetPipe().crtc->Get()->GetCtmProperty()) + return HWC2::Error::None; + + switch (color_transform_hint_) { + case HAL_COLOR_TRANSFORM_IDENTITY: + SetColorMarixToIdentity(); + break; + case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX: + color_matrix_ = std::make_shared<drm_color_ctm>(); + /* DRM expects a 3x3 matrix, but the HAL provides a 4x4 matrix. */ + for (int i = 0; i < kCtmCols; i++) { + for (int j = 0; j < kCtmRows; j++) { + constexpr int kInCtmRows = 4; + /* HAL matrix type is float, but DRM expects a s31.32 fix point */ + auto value = uint64_t(matrix[i * kInCtmRows + j] * float(1L << 32)); + color_matrix_->matrix[i * kCtmRows + j] = value; + } + } + break; + default: + return HWC2::Error::Unsupported; + } return HWC2::Error::None; } +bool HwcDisplay::CtmByGpu() { + if (color_transform_hint_ == HAL_COLOR_TRANSFORM_IDENTITY) + return false; + + if (GetPipe().crtc->Get()->GetCtmProperty()) + return false; + + if (GetHwc2()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore) + return false; + + return true; +} + HWC2::Error HwcDisplay::SetOutputBuffer(buffer_handle_t /*buffer*/, int32_t /*release_fence*/) { // TODO(nobody): Need virtual display support @@ -892,12 +936,31 @@ HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort, } HWC2::Error HwcDisplay::GetDisplayCapabilities(uint32_t *outNumCapabilities, - uint32_t * /*outCapabilities*/) { + uint32_t *outCapabilities) { if (outNumCapabilities == nullptr) { return HWC2::Error::BadParameter; } - *outNumCapabilities = 0; + bool skip_ctm = false; + + // Skip client CTM if user requested DRM_OR_IGNORE + if (GetHwc2()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore) + skip_ctm = true; + + // Skip client CTM if DRM can handle it + if (!skip_ctm && !IsInHeadlessMode() && + GetPipe().crtc->Get()->GetCtmProperty()) + skip_ctm = true; + + if (!skip_ctm) { + *outNumCapabilities = 0; + return HWC2::Error::None; + } + + *outNumCapabilities = 1; + if (outCapabilities) { + outCapabilities[0] = HWC2_DISPLAY_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM; + } return HWC2::Error::None; } diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h index 6cac60f..653aa4a 100644 --- a/hwc2_device/HwcDisplay.h +++ b/hwc2_device/HwcDisplay.h @@ -159,9 +159,7 @@ class HwcDisplay { return *pipeline_; } - android_color_transform_t &color_transform_hint() { - return color_transform_hint_; - } + bool CtmByGpu(); Stats &total_stats() { return total_stats_; @@ -194,8 +192,6 @@ class HwcDisplay { std::atomic_int flattenning_state_{ClientFlattenningState::NotRequired}; - constexpr static size_t MATRIX_SIZE = 16; - HwcDisplayConfigs configs_; DrmHwcTwo *const hwc2_; @@ -224,8 +220,10 @@ class HwcDisplay { std::map<hwc2_layer_t, HwcLayer> layers_; HwcLayer client_layer_; int32_t color_mode_{}; - std::array<float, MATRIX_SIZE> color_transform_matrix_{}; - android_color_transform_t color_transform_hint_; + static constexpr int kCtmRows = 3; + static constexpr int kCtmCols = 3; + std::shared_ptr<drm_color_ctm> color_matrix_; + android_color_transform_t color_transform_hint_{}; std::shared_ptr<DrmKmsPlan> current_plan_; @@ -234,6 +232,8 @@ class HwcDisplay { Stats prev_stats_; std::string DumpDelta(HwcDisplay::Stats delta); + void SetColorMarixToIdentity(); + HWC2::Error Init(); HWC2::Error SetActiveConfigInternal(uint32_t config, int64_t change_time); |