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
16 #include "rs_hdr_util.h"
17
18 #include "display_engine/rs_color_temperature.h"
19 #include "hdi_layer_info.h"
20 #include "metadata_helper.h"
21 #include "pipeline/main_thread/rs_main_thread.h"
22 #include "platform/common/rs_log.h"
23 #ifdef USE_VIDEO_PROCESSING_ENGINE
24 #include "render/rs_colorspace_convert.h"
25 #endif
26 #include "v2_1/cm_color_space.h"
27
28 namespace OHOS {
29 namespace Rosen {
30
31 constexpr float DEFAULT_HDR_RATIO = 1.0f;
32 constexpr float DEFAULT_SCALER = 1000.0f / 203.0f;
33 constexpr float GAMMA2_2 = 2.2f;
34 constexpr uint32_t DEFAULT_DYNAMIC_METADATA_SIZE = 50;
35 constexpr size_t MATRIX_SIZE = 9;
36
CheckIsHdrSurface(const RSSurfaceRenderNode & surfaceNode)37 HdrStatus RSHdrUtil::CheckIsHdrSurface(const RSSurfaceRenderNode& surfaceNode)
38 {
39 if (!surfaceNode.IsOnTheTree()) {
40 return HdrStatus::NO_HDR;
41 }
42 if (!surfaceNode.GetRSSurfaceHandler()) {
43 return HdrStatus::NO_HDR;
44 }
45 return CheckIsHdrSurfaceBuffer(surfaceNode.GetRSSurfaceHandler()->GetBuffer());
46 }
47
CheckIsHdrSurfaceBuffer(const sptr<SurfaceBuffer> surfaceBuffer)48 HdrStatus RSHdrUtil::CheckIsHdrSurfaceBuffer(const sptr<SurfaceBuffer> surfaceBuffer)
49 {
50 if (surfaceBuffer == nullptr) {
51 return HdrStatus::NO_HDR;
52 }
53 if (!RSSystemProperties::GetHdrVideoEnabled()) {
54 RS_LOGD("RSHdrUtil::CheckIsHdrSurfaceBuffer HDRVideoEnabled false");
55 return HdrStatus::NO_HDR;
56 }
57 #ifdef USE_VIDEO_PROCESSING_ENGINE
58 std::vector<uint8_t> metadataType{};
59 if (surfaceBuffer->GetMetadata(Media::VideoProcessingEngine::ATTRKEY_HDR_METADATA_TYPE, metadataType) ==
60 GSERROR_OK && metadataType.size() > 0 &&
61 metadataType[0] == HDI::Display::Graphic::Common::V2_1::CM_VIDEO_AI_HDR) {
62 return HdrStatus::AI_HDR_VIDEO;
63 }
64 #endif
65 if (surfaceBuffer->GetFormat() != GRAPHIC_PIXEL_FMT_RGBA_1010102 &&
66 surfaceBuffer->GetFormat() != GRAPHIC_PIXEL_FMT_YCBCR_P010 &&
67 surfaceBuffer->GetFormat() != GRAPHIC_PIXEL_FMT_YCRCB_P010) {
68 return HdrStatus::NO_HDR;
69 }
70 using namespace HDI::Display::Graphic::Common::V1_0;
71 CM_ColorSpaceInfo colorSpaceInfo;
72 if (MetadataHelper::GetColorSpaceInfo(surfaceBuffer, colorSpaceInfo) == GSERROR_OK) {
73 if (colorSpaceInfo.transfunc == TRANSFUNC_PQ || colorSpaceInfo.transfunc == TRANSFUNC_HLG) {
74 return HdrStatus::HDR_VIDEO;
75 }
76 }
77 return HdrStatus::NO_HDR;
78 }
79
CheckIsSurfaceWithMetadata(const RSSurfaceRenderNode & surfaceNode)80 bool RSHdrUtil::CheckIsSurfaceWithMetadata(const RSSurfaceRenderNode& surfaceNode)
81 {
82 if (!surfaceNode.IsOnTheTree()) {
83 return false;
84 }
85 if (!surfaceNode.GetRSSurfaceHandler()) {
86 return false;
87 }
88 return CheckIsSurfaceBufferWithMetadata(surfaceNode.GetRSSurfaceHandler()->GetBuffer());
89 }
90
CheckIsSurfaceBufferWithMetadata(const sptr<SurfaceBuffer> surfaceBuffer)91 bool RSHdrUtil::CheckIsSurfaceBufferWithMetadata(const sptr<SurfaceBuffer> surfaceBuffer)
92 {
93 if (surfaceBuffer == nullptr) {
94 return false;
95 }
96 using namespace HDI::Display::Graphic::Common::V1_0;
97 CM_ColorSpaceInfo colorSpaceInfo;
98 if (MetadataHelper::GetColorSpaceInfo(surfaceBuffer, colorSpaceInfo) != GSERROR_OK) {
99 RS_LOGD("RSHdrUtil::CheckIsSurfaceBufferWithMetadata failed to get ColorSpaceInfo");
100 return false;
101 }
102 // only primaries P3_D65 and BT2020 has metadata
103 if (colorSpaceInfo.primaries != CM_ColorPrimaries::COLORPRIMARIES_P3_D65 &&
104 colorSpaceInfo.primaries != CM_ColorPrimaries::COLORPRIMARIES_BT2020) {
105 RS_LOGD("RSHdrUtil::CheckIsSurfaceBufferWithMetadata colorSpaceInfo.primaries not satisfied");
106 return false;
107 }
108 #ifdef USE_VIDEO_PROCESSING_ENGINE
109 std::vector<uint8_t> dynamicMetadata{};
110 if (MetadataHelper::GetHDRDynamicMetadata(surfaceBuffer, dynamicMetadata) ==
111 GSERROR_OK && dynamicMetadata.size() > 0) {
112 return true;
113 }
114 #endif
115 return false;
116 }
117
UpdateSurfaceNodeNit(RSSurfaceRenderNode & surfaceNode,ScreenId screenId)118 void RSHdrUtil::UpdateSurfaceNodeNit(RSSurfaceRenderNode& surfaceNode, ScreenId screenId)
119 {
120 if (!surfaceNode.GetRSSurfaceHandler()) {
121 RS_LOGE("RSHdrUtil::UpdateSurfaceNodeNit surfaceHandler is NULL");
122 return;
123 }
124 const sptr<SurfaceBuffer>& surfaceBuffer = surfaceNode.GetRSSurfaceHandler()->GetBuffer();
125 if (surfaceBuffer == nullptr) {
126 RS_LOGE("surfaceNode.GetRSSurfaceHandler is NULL");
127 return;
128 }
129 auto& rsLuminance = RSLuminanceControl::Get();
130 if (surfaceNode.GetVideoHdrStatus() == HdrStatus::NO_HDR) {
131 surfaceNode.SetDisplayNit(rsLuminance.GetSdrDisplayNits(screenId));
132 surfaceNode.SetSdrNit(rsLuminance.GetSdrDisplayNits(screenId));
133 surfaceNode.SetBrightnessRatio(rsLuminance.GetHdrBrightnessRatio(screenId, 0));
134 // color temperature
135 if (surfaceNode.GetSdrHasMetadata()) {
136 UpdateSurfaceNodeLayerLinearMatrix(surfaceNode, screenId);
137 }
138 return;
139 }
140
141 using namespace HDI::Display::Graphic::Common::V1_0;
142 std::vector<uint8_t> hdrStaticMetadataVec;
143 std::vector<uint8_t> hdrDynamicMetadataVec;
144 GSError ret = GSERROR_OK;
145 #ifdef USE_VIDEO_PROCESSING_ENGINE
146 RSColorSpaceConvert::Instance().GetHDRStaticMetadata(surfaceBuffer, hdrStaticMetadataVec, ret);
147 RSColorSpaceConvert::Instance().GetHDRDynamicMetadata(surfaceBuffer, hdrDynamicMetadataVec, ret);
148 #endif
149 float scaler = DEFAULT_SCALER;
150 if (hdrStaticMetadataVec.size() != sizeof(HdrStaticMetadata) || hdrStaticMetadataVec.data() == nullptr) {
151 RS_LOGD("hdrStaticMetadataVec is invalid");
152 scaler = surfaceNode.GetHDRBrightness() * (scaler - 1.0f) + 1.0f;
153 } else {
154 const auto& data = *reinterpret_cast<HdrStaticMetadata*>(hdrStaticMetadataVec.data());
155 scaler = rsLuminance.CalScaler(data.cta861.maxContentLightLevel, ret == GSERROR_OK ?
156 hdrDynamicMetadataVec.size() : DEFAULT_DYNAMIC_METADATA_SIZE, surfaceNode.GetHDRBrightness());
157 }
158
159 float sdrNits = rsLuminance.GetSdrDisplayNits(screenId);
160 float displayNits = rsLuminance.GetDisplayNits(screenId);
161
162 float layerNits = std::clamp(sdrNits * scaler, sdrNits, displayNits);
163 surfaceNode.SetDisplayNit(layerNits);
164 surfaceNode.SetSdrNit(sdrNits);
165 if (ROSEN_LE(displayNits, 0.0f)) {
166 surfaceNode.SetBrightnessRatio(DEFAULT_HDR_RATIO);
167 } else {
168 surfaceNode.SetBrightnessRatio(std::pow(layerNits / displayNits, 1.0f / GAMMA2_2)); // gamma 2.2
169 }
170 // color temperature
171 UpdateSurfaceNodeLayerLinearMatrix(surfaceNode, screenId);
172 RS_LOGD("RSHdrUtil::UpdateSurfaceNodeNit layerNits: %{public}.2f, displayNits: %{public}.2f,"
173 " sdrNits: %{public}.2f, scaler: %{public}.2f, HDRBrightness: %{public}f", layerNits, displayNits, sdrNits,
174 scaler, surfaceNode.GetHDRBrightness());
175 }
176
UpdateSurfaceNodeLayerLinearMatrix(RSSurfaceRenderNode & surfaceNode,ScreenId screenId)177 void RSHdrUtil::UpdateSurfaceNodeLayerLinearMatrix(RSSurfaceRenderNode& surfaceNode, ScreenId screenId)
178 {
179 if (!surfaceNode.GetRSSurfaceHandler()) {
180 RS_LOGE("RSHdrUtil::UpdateSurfaceNodeLayerLinearMatrix surfaceHandler is NULL");
181 return;
182 }
183 const sptr<SurfaceBuffer>& surfaceBuffer = surfaceNode.GetRSSurfaceHandler()->GetBuffer();
184 if (surfaceBuffer == nullptr) {
185 RS_LOGE("surfaceNode.GetRSSurfaceHandler is NULL");
186 return;
187 }
188 using namespace HDI::Display::Graphic::Common::V1_0;
189 CM_ColorSpaceInfo srcColorSpaceInfo;
190 CM_Matrix srcColorMatrix = CM_Matrix::MATRIX_P3;
191 if (MetadataHelper::GetColorSpaceInfo(surfaceBuffer, srcColorSpaceInfo) == GSERROR_OK) {
192 srcColorMatrix = srcColorSpaceInfo.matrix;
193 }
194 std::vector<uint8_t> hdrDynamicMetadataVec;
195 GSError ret = GSERROR_OK;
196 #ifdef USE_VIDEO_PROCESSING_ENGINE
197 RSColorSpaceConvert::Instance().GetHDRDynamicMetadata(surfaceBuffer, hdrDynamicMetadataVec, ret);
198 #endif
199 std::vector<float> layerLinearMatrix = RSColorTemperature::Get().GetLayerLinearCct(screenId,
200 ret == GSERROR_OK ? hdrDynamicMetadataVec : std::vector<uint8_t>(), srcColorMatrix);
201 surfaceNode.SetLayerLinearMatrix(layerLinearMatrix);
202 if (layerLinearMatrix.size() >= MATRIX_SIZE) {
203 // main diagonal indices of a 3x3 matrix are 0, 4 and 8
204 RS_LOGD("RSHdrUtil::UpdateSurfaceNodeLayerLinearMatrix "
205 "matrix[0]: %{public}.2f, matrix[4]: %{public}.2f, matrix[8]: %{public}.2f",
206 layerLinearMatrix[0], layerLinearMatrix[4], layerLinearMatrix[8]);
207 }
208 }
209
UpdatePixelFormatAfterHwcCalc(RSDisplayRenderNode & node)210 void RSHdrUtil::UpdatePixelFormatAfterHwcCalc(RSDisplayRenderNode& node)
211 {
212 const auto& selfDrawingNodes = RSMainThread::Instance()->GetSelfDrawingNodes();
213 for (const auto& selfDrawingNode : selfDrawingNodes) {
214 if (!selfDrawingNode || !selfDrawingNode->GetAncestorDisplayNode().lock()) {
215 RS_LOGD("RSHdrUtil::UpdatePixelFormatAfterHwcCalc selfDrawingNode or ancestoreNode is nullptr");
216 continue;
217 }
218 auto ancestor = selfDrawingNode->GetAncestorDisplayNode().lock()->ReinterpretCastTo<RSDisplayRenderNode>();
219 if (ancestor != nullptr && node.GetId() == ancestor->GetId()) {
220 CheckPixelFormatWithSelfDrawingNode(*selfDrawingNode, node);
221 }
222 }
223 }
224
CheckPixelFormatWithSelfDrawingNode(RSSurfaceRenderNode & surfaceNode,RSDisplayRenderNode & displayNode)225 void RSHdrUtil::CheckPixelFormatWithSelfDrawingNode(RSSurfaceRenderNode& surfaceNode,
226 RSDisplayRenderNode& displayNode)
227 {
228 if (!surfaceNode.IsOnTheTree()) {
229 RS_LOGD("RSHdrUtil::CheckPixelFormatWithSelfDrawingNode node(%{public}s) is not on the tree",
230 surfaceNode.GetName().c_str());
231 return;
232 }
233 if (!surfaceNode.GetRSSurfaceHandler()) {
234 RS_LOGD("RSHdrUtil::CheckPixelFormatWithSelfDrawingNode surfaceHandler is null");
235 return;
236 }
237 auto screenId = displayNode.GetScreenId();
238 UpdateSurfaceNodeNit(surfaceNode, screenId);
239 displayNode.CollectHdrStatus(surfaceNode.GetVideoHdrStatus());
240 if (RSLuminanceControl::Get().IsForceCloseHdr()) {
241 RS_LOGD("RSHdrUtil::CheckPixelFormatWithSelfDrawingNode node(%{public}s) forceCloseHdr.",
242 surfaceNode.GetName().c_str());
243 return;
244 }
245 if (!surfaceNode.IsHardwareForcedDisabled()) {
246 RS_LOGD("RSHdrUtil::CheckPixelFormatWithSelfDrawingNode node(%{public}s) is hardware-enabled",
247 surfaceNode.GetName().c_str());
248 return;
249 }
250 if (surfaceNode.GetVideoHdrStatus() != HdrStatus::NO_HDR) {
251 SetHDRParam(surfaceNode, true);
252 if (displayNode.GetIsLuminanceStatusChange()) {
253 surfaceNode.SetContentDirty();
254 }
255 displayNode.SetPixelFormat(GRAPHIC_PIXEL_FMT_RGBA_1010102);
256 RS_LOGD("RSHdrUtil::CheckPixelFormatWithSelfDrawingNode HDRService pixelformat is set to 1010102");
257 }
258 }
259
SetHDRParam(RSSurfaceRenderNode & node,bool flag)260 void RSHdrUtil::SetHDRParam(RSSurfaceRenderNode& node, bool flag)
261 {
262 auto firstLevelNode = RSBaseRenderNode::ReinterpretCast<RSSurfaceRenderNode>(node.GetFirstLevelNode());
263 if (firstLevelNode != nullptr && node.GetFirstLevelNodeId() != node.GetId()) {
264 firstLevelNode->SetHDRPresent(flag);
265 }
266 node.SetHDRPresent(flag);
267 }
268
269 } // namespace Rosen
270 } // namespace OHOS