drm_hwcomposer: Correct CTM conversion
Correctly compute the CTM given the HAL interface.
HAL provides a 4x4 float type matrix:
| 0 1 2 3|
| 4 5 6 7|
| 8 9 10 11|
|12 13 14 15|
This is to be interpreted as
out matrix in offset
|R| |0 4 8| |R| |12|
|G| = |1 5 9| x |G| + |13|
|B| |2 6 10| |B| |14|
DRM expects a 3x3 s31.32 fixed point matrix interpreted as
|R| |0 1 2| |R|
|G| = |3 4 5| x |G|
|B| |6 7 8| |B|
DRM does not support an offset vector, so we reject any color transform
matrices that have one.
Change-Id: I323fde281c8a97cf319bb9774eb232abcc8bde34
Signed-off-by: Sasha McIntosh <sashamcintosh@google.com>
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 3b9dfd9..7772175 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -709,6 +709,15 @@
#include <xf86drmMode.h>
+static uint64_t To3132FixPt(float in) {
+ constexpr uint64_t kSignMask = (1ULL << 63);
+ constexpr uint64_t kValueMask = ~(1ULL << 63);
+ constexpr auto kValueScale = static_cast<float>(1ULL << 32);
+ if (in < 0)
+ return (static_cast<uint64_t>(-in * kValueScale) & kValueMask) | kSignMask;
+ return static_cast<uint64_t>(in * kValueScale) & kValueMask;
+}
+
HWC2::Error HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) {
if (hint < HAL_COLOR_TRANSFORM_IDENTITY ||
hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)
@@ -730,14 +739,37 @@
SetColorMatrixToIdentity();
break;
case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX:
+ // Without HW support, we cannot correctly process matrices with an offset.
+ for (int i = 12; i < 14; i++) {
+ if (matrix[i] != 0.F)
+ return HWC2::Error::Unsupported;
+ }
+
+ /* HAL provides a 4x4 float type matrix:
+ * | 0 1 2 3|
+ * | 4 5 6 7|
+ * | 8 9 10 11|
+ * |12 13 14 15|
+ *
+ * R_out = R*0 + G*4 + B*8 + 12
+ * G_out = R*1 + G*5 + B*9 + 13
+ * B_out = R*2 + G*6 + B*10 + 14
+ *
+ * DRM expects a 3x3 s31.32 fixed point matrix:
+ * out matrix in
+ * |R| |0 1 2| |R|
+ * |G| = |3 4 5| x |G|
+ * |B| |6 7 8| |B|
+ *
+ * R_out = R*0 + G*1 + B*2
+ * G_out = R*3 + G*4 + B*5
+ * B_out = R*6 + G*7 + B*8
+ */
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(1ULL << 32));
- color_matrix_->matrix[i * kCtmRows + j] = value;
+ color_matrix_->matrix[i * kCtmRows + j] = To3132FixPt(matrix[j * kInCtmRows + i]);
}
}
break;