1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "ge_tone_mapping_helper.h"
16
17 #include <algorithm>
18 #include <mutex>
19
20 #include "ge_edge_light_shader_filter.h"
21 #include "ge_log.h"
22
23 namespace OHOS {
24 namespace Rosen {
25
26 namespace {
27 // Bezier curves describing tone mapping rule, anchors define
28 const std::vector<Vector2f> g_hdrCurveAnchors = {
29 {0.0f, 0.0f}, {0.75f, 0.75f}, {1.0f, 0.95f}, {1.25f, 0.97f},
30 {1.5f, 0.98f}, {1.75f, 0.9875f}, {1.90f, 0.995f}, {2.0f, 1.0f},
31 };
32
33 // Bezier curves describing tone mapping rule, control points define
34 const std::vector<Vector2f> g_hdrCurveControlPoint = {
35 {0.375f, 0.375f}, {0.875f, 0.875f}, {1.125f, 0.9625f}, {1.375f, 0.9725f},
36 {1.625f, 0.98f}, {1.825f, 0.99f}, {1.95f, 0.998f}, // 1 less than anchors
37 };
38
39 constexpr float SDR_LUMINANCE = 1.0f;
40 } // namespace
41
GetBrightnessMapping(float headroom,Vector4f & input)42 Vector4f GEToneMappingHelper::GetBrightnessMapping(float headroom, Vector4f& input)
43 {
44 float highValue = std::max({input.x_, input.y_, input.z_, SDR_LUMINANCE});
45 float compressRatio = GetBrightnessMapping(headroom, highValue) / highValue;
46 Vector4f output;
47 output.x_ = input.x_ * compressRatio;
48 output.y_ = input.y_ * compressRatio;
49 output.z_ = input.z_ * compressRatio;
50 output.w_ = input.w_;
51 return output;
52 }
53
GetBrightnessMapping(float headroom,float input)54 float GEToneMappingHelper::GetBrightnessMapping(float headroom, float input)
55 {
56 if (ROSEN_GE(headroom, EFFECT_MAX_LUMINANCE)) {
57 return input;
58 }
59 int rangeIndex = -1;
60 for (auto point : g_hdrCurveAnchors) {
61 if (input <= point.x_) {
62 break;
63 }
64 rangeIndex++;
65 }
66 if (rangeIndex == -1) {
67 return 0.0f;
68 }
69 if ((rangeIndex >= static_cast<int>(g_hdrCurveAnchors.size()) - 1) ||
70 (rangeIndex >= static_cast<int>(g_hdrCurveControlPoint.size()))) {
71 return headroom;
72 }
73
74 // calculate new hdr bightness via bezier curve
75 Vector2f start = g_hdrCurveAnchors[rangeIndex];
76 Vector2f end = g_hdrCurveAnchors[rangeIndex + 1];
77 Vector2f control = g_hdrCurveControlPoint[rangeIndex];
78
79 float y = 0.0f;
80 if (CalcBezierResultY(start, end, control, input, y)) {
81 y = ((EFFECT_MAX_LUMINANCE - headroom) * y + (headroom - SDR_LUMINANCE) * input) /
82 (EFFECT_MAX_LUMINANCE - SDR_LUMINANCE); // linear interpolation
83 LOGD("GEToneMappingHelper::GetBrightnessMapping y is %{public}f", y);
84 return std::clamp(y, 0.0f, headroom);
85 }
86 return std::clamp(input, 0.0f, headroom);
87 }
88
GetBrightnessMapping(float brightness,Drawing::Color4f & input)89 Drawing::Color4f GEToneMappingHelper::GetBrightnessMapping(float brightness, Drawing::Color4f& input)
90 {
91 float highValue = std::max({input.redF_, input.greenF_, input.blueF_, SDR_LUMINANCE});
92 float compressRatio = GetBrightnessMapping(brightness, highValue) / highValue;
93 Drawing::Color4f output;
94 output.redF_ = input.redF_ * compressRatio;
95 output.greenF_ = input.greenF_ * compressRatio;
96 output.blueF_ = input.blueF_ * compressRatio;
97 output.alphaF_ = input.alphaF_;
98 return output;
99 }
100
CalcBezierResultY(const Vector2f & start,const Vector2f & end,const Vector2f & control,float x,float & y)101 bool GEToneMappingHelper::CalcBezierResultY(
102 const Vector2f& start, const Vector2f& end, const Vector2f& control, float x, float& y)
103 {
104 const float a = start[0] - 2 * control[0] + end[0];
105 const float b = 2 * (control[0] - start[0]);
106 const float c = start[0] - x;
107 const float discriminant = b * b - 4 * a * c;
108
109 float t = 0.0f;
110 if (ROSEN_LNE(discriminant, 0.0f)) {
111 return false;
112 } else if (ROSEN_EQ(a, 0.0f)) {
113 t = -c / b;
114 } else {
115 const float sqrtD = std::sqrt(discriminant);
116 const float t1 = (-b + sqrtD) / (2.0 * a);
117 const float t2 = (-b - sqrtD) / (2.0 * a);
118 if (ROSEN_GE(t1, 0.0f) && ROSEN_LE(t1, 1.0f)) {
119 t = t1;
120 } else if (ROSEN_GE(t2, 0.0f) && ROSEN_LE(t2, 1.0f)) {
121 t = t2;
122 }
123 }
124
125 y = start[1] + t * (2.0f * (control[1] - start[1]) + t * (start[1] - 2.0f * control[1] + end[1]));
126 return true;
127 }
128
129 } // Rosen
130 } // OHOS
131