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>
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 @@
}
}
+ 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
return scale_with_gpu_;
}
+ auto &GetCtmHandling() const {
+ return ctm_handling_;
+ }
+
auto &GetMainLock() {
return main_lock_;
}
@@ -65,7 +74,9 @@
std::vector<std::unique_ptr<DrmDevice>> drms_;
+ // Android properties:
bool scale_with_gpu_{};
+ CtmHandling ctm_handling_{};
std::shared_ptr<UEventListener> uevent_listener_;