From 6239b02b0c0b24267566926ed62b8723a3b69d5f Mon Sep 17 00:00:00 2001 From: linpeter Date: Wed, 7 Nov 2018 04:08:18 +0800 Subject: hwc2: White point compensation for Adaptive color mode Adaptive color doesn't have white point calibration. Using transfer matrix to compensate white point. Compensted values are saved in persist/display/calibrated_rgb. Bug: 116282483 Test: switch color mode and check transfer matrix adb shell vndservice call display.qservice 399 i32 0 i32 0 Check dump rgb value adb shell vndservice call display.qservice 21 i32 1 i32 1 i32 2 Change-Id: Iaa7a5f8ccc58be8ecdcfebe814cf7660ef34cc93 Signed-off-by: linpeter --- include/display_properties.h | 1 + libqservice/IQService.h | 1 + sdm/libs/hwc2/hwc_display.cpp | 128 ++++++++++++++++++++++++++++++++-- sdm/libs/hwc2/hwc_display.h | 61 ++++++++++++++++ sdm/libs/hwc2/hwc_display_primary.cpp | 12 ++++ sdm/libs/hwc2/hwc_display_primary.h | 1 + sdm/libs/hwc2/hwc_session.cpp | 20 ++++++ sdm/libs/hwc2/hwc_session.h | 1 + 8 files changed, 219 insertions(+), 6 deletions(-) diff --git a/include/display_properties.h b/include/display_properties.h index 3944dc65..06f4e64f 100644 --- a/include/display_properties.h +++ b/include/display_properties.h @@ -94,6 +94,7 @@ #define ENABLE_DEFAULT_COLOR_MODE DISPLAY_PROP("enable_default_color_mode") #define DISABLE_HDR DISPLAY_PROP("disable_hdr") #define DATASPACE_SATURATION_MATRIX_PROP DISPLAY_PROP("dataspace_saturation_matrix") +#define WHITE_POINT_COMPENSATED_COEFFICIENT_PROP DISPLAY_PROP("white_point_compensated_coefficient") #define HDR_CONFIG_PROP RO_DISPLAY_PROP("hdr.config") #define QDCM_PCC_TRANS_PROP DISPLAY_PROP("qdcm.pcc_for_trans") diff --git a/libqservice/IQService.h b/libqservice/IQService.h index b2012560..e9af5a17 100644 --- a/libqservice/IQService.h +++ b/libqservice/IQService.h @@ -79,6 +79,7 @@ public: GET_COMPOSER_STATUS = 37, // Get composer init status-true if primary display init is done SET_COLOR_MODE_WITH_RENDER_INTENT = 38, SET_IDLE_PC = 39, // Enable/disable Idle power collapse + SET_WHITE_POINT_COMPENSATION = 399, // Enable/disable white point compensation COMMAND_LIST_END = 400, }; diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp index 4d292632..03e4cc36 100644 --- a/sdm/libs/hwc2/hwc_display.cpp +++ b/sdm/libs/hwc2/hwc_display.cpp @@ -54,6 +54,8 @@ HWCColorMode::HWCColorMode(DisplayInterface *display_intf) : display_intf_(displ HWC2::Error HWCColorMode::Init() { PopulateColorModes(); + if (GetWhitePointCompensatedCoefficients()) + white_point_compensated_ = PaserWhitePointCompensatedData(); return ApplyDefaultColorMode(); } @@ -121,11 +123,13 @@ HWC2::Error HWCColorMode::SetColorModeWithRenderIntent(ColorMode mode, RenderInt DLOGE("failed for mode = %d intent = %d name = %s", mode, intent, mode_string.c_str()); return HWC2::Error::Unsupported; } - // The mode does not have the PCC configured, restore the transform - RestoreColorTransform(); current_color_mode_ = mode; current_render_intent_ = intent; + + // The mode does not have the PCC configured, restore the transform + RestoreColorTransform(); + DLOGV_IF(kTagClient, "Successfully applied mode = %d intent = %d name = %s", mode, intent, mode_string.c_str()); return HWC2::Error::None; @@ -141,8 +145,23 @@ HWC2::Error HWCColorMode::SetColorModeById(int32_t color_mode_id) { return HWC2::Error::None; } +HWC2::Error HWCColorMode::SetWhitePointCompensation(bool enabled) { + white_point_compensated_ = enabled; + if (white_point_compensated_) { + PaserWhitePointCompensatedData(); + ApplyWhitePointCompensationToMatrix(white_point_compensated_color_matrix_, color_matrix_); + } + + RestoreColorTransform(); + + DLOGI("Set White Point Compensation: %d", enabled); + return HWC2::Error::None; +} + HWC2::Error HWCColorMode::RestoreColorTransform() { - DisplayError error = display_intf_->SetColorTransform(kColorTransformMatrixCount, color_matrix_); + + DisplayError error = display_intf_->SetColorTransform(kColorTransformMatrixCount, + GetTransferMatrix()); if (error != kErrorNone) { DLOGE("Failed to set Color Transform"); return HWC2::Error::BadParameter; @@ -151,19 +170,106 @@ HWC2::Error HWCColorMode::RestoreColorTransform() { return HWC2::Error::None; } +bool HWCColorMode::PaserWhitePointCompensatedData() { + static constexpr char kWhitePointCalibrationDataPath[] = "/persist/display/calibrated_rgb"; + FILE *fp = fopen(kWhitePointCalibrationDataPath, "r"); + int compensated_red = 0; + int compensated_green = 0; + int compensated_blue = 0; + + if (!fp) { + compensated_red_ratio_ = 1.0; + compensated_green_ratio_ = 1.0; + compensated_blue_ratio_ = 1.0; + return false; + } + + fscanf(fp, "%d %d %d", &compensated_red, &compensated_green, &compensated_blue); + + fclose(fp); + + // r = r_coeffient2 * R^2 + r_coeffient1 * R + r_coeffient0 + // g = g_coeffient2 * G^2 + g_coeffient1 * G + g_coeffient0 + // b = b_coeffient2 * B^2 + b_coeffient1 * B + b_coeffient0 + // r_ratio = r/kCompensatedMaxRGB + // g_ratio = g/kCompensatedMaxRGB + // b_ratio = b/kCompensatedMaxRGB + auto rgb_ratio = [=](int rgb, float c2, float c1, float c0) { + return ((c2 * rgb * rgb + c1 * rgb + c0) / kCompensatedMaxRGB);}; + + compensated_red_ratio_ = rgb_ratio(CheckCompensatedRGB(compensated_red), white_point_compensated_Coefficients_[0], + white_point_compensated_Coefficients_[1], white_point_compensated_Coefficients_[2]); + compensated_green_ratio_ = rgb_ratio(CheckCompensatedRGB(compensated_green), white_point_compensated_Coefficients_[3], + white_point_compensated_Coefficients_[4], white_point_compensated_Coefficients_[5]); + compensated_blue_ratio_ = rgb_ratio(CheckCompensatedRGB(compensated_blue), white_point_compensated_Coefficients_[6], + white_point_compensated_Coefficients_[7], white_point_compensated_Coefficients_[8]); + return true; +} + +bool HWCColorMode::GetWhitePointCompensatedCoefficients() { + char value[kPropertyMax] = {}; + if (Debug::Get()->GetProperty(WHITE_POINT_COMPENSATED_COEFFICIENT_PROP, value) != kErrorNone) { + DLOGW("Undefined Compensated Coefficients"); + return false; + } + + std::string value_string(value); + std::size_t start = 0, end = 0; + int index = 0; + // We need 9 coneffients, 3 for red, 3 for green, 3 for blue. + float CompensatedCoefficients[kCompensatedCoefficientElements] = { 1.0, 1.0, 1.0, \ + 1.0, 1.0, 1.0, \ + 1.0, 1.0, 1.0 }; + + // The property must have kCompensatedCoefficientElements delimited by commas + while ((end = value_string.find(",", start)) != std::string::npos) { + CompensatedCoefficients[index] = std::stof(value_string.substr(start, end - start)); + start = end + 1; + index++; + if (index > kCompensatedCoefficientElements - 1) { + DLOGW("Over Compensated Coefficients defined"); + return false; + } + } + + if (index < kCompensatedCoefficientElements - 1) { + DLOGW("Less Compensated Coefficients defined"); + return false; + } + + CompensatedCoefficients[index] = std::stof(value_string.substr(start, end - start)); + + for (int32_t i = 0; i < kCompensatedCoefficientElements; i++) { + white_point_compensated_Coefficients_[i] = CompensatedCoefficients[i]; + DLOGD("CompensatedCoefficients[%d]=%f",i, CompensatedCoefficients[i]); + } + return true; +} + HWC2::Error HWCColorMode::SetColorTransform(const float *matrix, android_color_transform_t /*hint*/) { DTRACE_SCOPED(); auto status = HWC2::Error::None; double color_matrix[kColorTransformMatrixCount] = {0}; + double white_point_compensated_color_matrix[kColorTransformMatrixCount] = {0}; CopyColorTransformMatrix(matrix, color_matrix); - DisplayError error = display_intf_->SetColorTransform(kColorTransformMatrixCount, color_matrix); + if (white_point_compensated_) + ApplyWhitePointCompensationToMatrix(white_point_compensated_color_matrix, color_matrix); + + DisplayError error = display_intf_->SetColorTransform(kColorTransformMatrixCount, + NeedWhitePointCompensated() ? + white_point_compensated_color_matrix : + color_matrix); if (error != kErrorNone) { DLOGE("Failed to set Color Transform Matrix"); status = HWC2::Error::Unsupported; } CopyColorTransformMatrix(matrix, color_matrix_); + + if (white_point_compensated_) + CopyColorTransformMatrix(white_point_compensated_color_matrix, white_point_compensated_color_matrix_); + return status; } @@ -312,13 +418,23 @@ void HWCColorMode::Dump(std::ostringstream* os) { } *os << "current mode: " << static_cast(current_color_mode_) << std::endl; *os << "current render_intent: " << static_cast(current_render_intent_) << std::endl; + *os << "Need white point compensated: " << NeedWhitePointCompensated() << ",RGB:[" + << std::fixed << std::setprecision(4) + << compensated_red_ratio_ << "," + << compensated_green_ratio_ << "," + << compensated_blue_ratio_ << "] "<< std::endl; + *os << "current transform: "; + double color_matrix[kColorTransformMatrixCount] = {0}; + + CopyColorTransformMatrix(GetTransferMatrix(), color_matrix); + for (uint32_t i = 0; i < kColorTransformMatrixCount; i++) { if (i % 4 == 0) { *os << std::endl; } - *os << std::fixed << std::setprecision(2) << std::setw(6) << std::setfill(' ') - << color_matrix_[i] << " "; + *os << std::fixed << std::setprecision(4) << std::setw(8) << std::setfill(' ') + << color_matrix[i] << " "; } *os << std::endl; } diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h index 49406785..ff072174 100644 --- a/sdm/libs/hwc2/hwc_display.h +++ b/sdm/libs/hwc2/hwc_display.h @@ -73,6 +73,7 @@ class HWCColorMode { HWC2::Error RestoreColorTransform(); PrimariesTransfer GetWorkingColorSpace(); ColorMode GetCurrentColorMode() { return current_color_mode_; } + HWC2::Error SetWhitePointCompensation(bool enabled); private: static const uint32_t kColorTransformMatrixCount = 16; @@ -97,6 +98,65 @@ class HWCColorMode { 0.0, 1.0, 0.0, 0.0, \ 0.0, 0.0, 1.0, 0.0, \ 0.0, 0.0, 0.0, 1.0 }; + /* + * Transform matrix is 4 x 4 + * |r.r r.g r.b 0| + * |g.r g.g g.b 0| + * |b.r b.g b.b 0| + * |T.r T.g T.b 1| + * R_out = R_in * r.r + G_in * g.r + B_in * b.r + Tr + * G_out = R_in * r.g + G_in * g.g + B_in * b.g + Tg + * B_out = R_in * r.b + G_in * g.b + B_in * b.b + Tb + * + * Cr, Cg, Cb for white point compensation + * |r.r*Cr r.g*Cg r.b*Cb 0| + * |g.r*Cr g.g*Cg g.b*Cb 0| + * |b.r*Cr b.g*Cg b.b*Cb 0| + * |T.r*Cr T.g*Cg T.b*Cb 1| + * R_out = R_in * r.r * Cr + G_in * g.r * Cr + B_in * b.r * Cr + Tr * Cr + * G_out = R_in * r.g * Cg + G_in * g.g * Cg + B_in * b.g * Cg + Tg * Cg + * B_out = R_in * r.b * Cb + G_in * g.b * Cb + B_in * b.b * Cb + Tb * Cb + */ + static constexpr int kCompensatedMaxRGB = 255; + static constexpr int kCompensatedMinRGB = 230; + static constexpr int kCompensatedCoefficientElements = 9; + double white_point_compensated_color_matrix_[kColorTransformMatrixCount] = { + 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 }; + bool PaserWhitePointCompensatedData(); + float white_point_compensated_Coefficients_[kCompensatedCoefficientElements] = { + 1.0, 1.0, 1.0, \ + 1.0, 1.0, 1.0, \ + 1.0, 1.0, 1.0 }; + + bool GetWhitePointCompensatedCoefficients(); + bool NeedWhitePointCompensated() { return (current_render_intent_ == RenderIntent::ENHANCE) && + white_point_compensated_; } + double * GetTransferMatrix() { return NeedWhitePointCompensated() ? white_point_compensated_color_matrix_ + : color_matrix_;} + bool white_point_compensated_ = false; + double compensated_red_ratio_ = 1.0; + double compensated_green_ratio_ = 1.0; + double compensated_blue_ratio_ = 1.0; + inline static constexpr int CheckCompensatedRGB (int value) { + return ((value < kCompensatedMinRGB) ? kCompensatedMinRGB : + (value > kCompensatedMaxRGB) ? kCompensatedMaxRGB : value); + } + + void ApplyWhitePointCompensationToMatrix(double *out, double *in) { + for (uint32_t i = 0; i < kColorTransformMatrixCount; i++) { + if ((i % 4) == 0) + out[i] = compensated_red_ratio_ * in[i]; + else if ((i % 4) == 1) + out[i] = compensated_green_ratio_ * in[i]; + else if ((i % 4) == 2) + out[i] = compensated_blue_ratio_ * in[i]; + else if ((i % 4) == 3) + out[i] = in[i]; + } + } }; class HWCDisplay : public DisplayEventHandler { @@ -202,6 +262,7 @@ class HWCDisplay : public DisplayEventHandler { virtual HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence, int32_t dataspace, hwc_region_t damage); virtual HWC2::Error SetColorMode(ColorMode mode) { return HWC2::Error::Unsupported; } + virtual HWC2::Error SetWhitePointCompensation(bool enabled) { return HWC2::Error::Unsupported; } virtual HWC2::Error SetColorModeWithRenderIntent(ColorMode mode, RenderIntent intent) { return HWC2::Error::Unsupported; } diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp index f5970cd8..b1eeecdf 100644 --- a/sdm/libs/hwc2/hwc_display_primary.cpp +++ b/sdm/libs/hwc2/hwc_display_primary.cpp @@ -339,6 +339,18 @@ HWC2::Error HWCDisplayPrimary::SetColorMode(ColorMode mode) { return SetColorModeWithRenderIntent(mode, RenderIntent::COLORIMETRIC); } +HWC2::Error HWCDisplayPrimary::SetWhitePointCompensation(bool enabled) { + auto status = color_mode_->SetWhitePointCompensation(enabled); + if (status != HWC2::Error::None) { + DLOGE("failed for SetWhitePointCompensation to %d", enabled); + return status; + } + + callbacks_->Refresh(HWC_DISPLAY_PRIMARY); + + return status; +} + HWC2::Error HWCDisplayPrimary::SetColorModeWithRenderIntent(ColorMode mode, RenderIntent intent) { auto status = color_mode_->SetColorModeWithRenderIntent(mode, intent); if (status != HWC2::Error::None) { diff --git a/sdm/libs/hwc2/hwc_display_primary.h b/sdm/libs/hwc2/hwc_display_primary.h index 40f0f489..d6dcc530 100644 --- a/sdm/libs/hwc2/hwc_display_primary.h +++ b/sdm/libs/hwc2/hwc_display_primary.h @@ -58,6 +58,7 @@ class HWCDisplayPrimary : public HWCDisplay { virtual HWC2::Error Present(int32_t *out_retire_fence); virtual HWC2::Error GetColorModes(uint32_t *out_num_modes, ColorMode *out_modes); virtual HWC2::Error SetColorMode(ColorMode mode); + virtual HWC2::Error SetWhitePointCompensation(bool enabled); virtual HWC2::Error GetRenderIntents(ColorMode mode, uint32_t *out_num_intents, RenderIntent *out_intents); virtual HWC2::Error SetColorModeWithRenderIntent(ColorMode mode, RenderIntent intent); diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp index e4404648..2691a42f 100644 --- a/sdm/libs/hwc2/hwc_session.cpp +++ b/sdm/libs/hwc2/hwc_session.cpp @@ -1355,6 +1355,14 @@ android::status_t HWCSession::notifyCallback(uint32_t command, const android::Pa status = SetIdlePC(input_parcel); break; + case qService::IQService::SET_WHITE_POINT_COMPENSATION: + if (!input_parcel) { + DLOGE("QService command = %d: input_parcel needed.", command); + break; + } + status = SetWhitePointCompensation(input_parcel); + break; + default: DLOGW("QService command = %d is not supported.", command); break; @@ -1551,6 +1559,18 @@ android::status_t HWCSession::SetColorModeOverride(const android::Parcel *input_ return 0; } +android::status_t HWCSession::SetWhitePointCompensation(const android::Parcel *input_parcel) { + auto display = static_cast(input_parcel->readInt32()); + auto enabled = static_cast(input_parcel->readInt32()); + auto device = static_cast(this); + + auto err = CallDisplayFunction(device, display, &HWCDisplay::SetWhitePointCompensation, enabled); + if (err != HWC2_ERROR_NONE) + return -EINVAL; + + return 0; +} + android::status_t HWCSession::SetColorModeWithRenderIntentOverride( const android::Parcel *input_parcel) { auto display = static_cast(input_parcel->readInt32()); diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h index 5b94b572..8eb70167 100644 --- a/sdm/libs/hwc2/hwc_session.h +++ b/sdm/libs/hwc2/hwc_session.h @@ -271,6 +271,7 @@ class HWCSession : hwc2_device_t, HWCUEventListener, IDisplayConfig, public qCli android::status_t SetMixerResolution(const android::Parcel *input_parcel); android::status_t SetColorModeOverride(const android::Parcel *input_parcel); android::status_t SetColorModeWithRenderIntentOverride(const android::Parcel *input_parcel); + android::status_t SetWhitePointCompensation(const android::Parcel *input_parcel); android::status_t SetColorModeById(const android::Parcel *input_parcel); android::status_t getComposerStatus(); -- cgit v1.2.3