aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Stratiienko <r.stratiienko@gmail.com>2023-01-17 18:06:04 +0200
committerRoman Stratiienko <r.stratiienko@gmail.com>2023-01-18 17:20:01 +0200
commit0da91bf5bb72323a0f0d1928a1fc36a01c1b7941 (patch)
treec9c41c3efc5aa707acc0a23d4108ce69cd2fa3c6
parent359a9d397100cf531f203ded61d2578957fb526f (diff)
downloaddrm_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.cpp3
-rw-r--r--drm/DrmAtomicStateManager.cpp14
-rw-r--r--drm/DrmAtomicStateManager.h2
-rw-r--r--drm/DrmCrtc.cpp5
-rw-r--r--drm/DrmCrtc.h6
-rw-r--r--drm/ResourceManager.cpp18
-rw-r--r--drm/ResourceManager.h11
-rw-r--r--hwc2_device/HwcDisplay.cpp93
-rw-r--r--hwc2_device/HwcDisplay.h14
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);