1 /*
2 * Copyright (c) 2024 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 "render/rs_colorspace_convert.h"
16
17 #include <dlfcn.h>
18
19 #include "effect/image_filter.h"
20 #include "luminance/rs_luminance_control.h"
21 #include "metadata_helper.h"
22 #include "platform/common/rs_log.h"
23
24 namespace OHOS {
25 namespace Rosen {
26
27 namespace {
28 constexpr float DEFAULT_HDR_RATIO = 1.0f;
29 constexpr float REFERENCE_WHITE = 203.0f;
30 constexpr float CAMERA_WHITE_MIN = 500.0f;
31 constexpr float CAMERA_WHITE_MAX = 510.0f;
32 constexpr float CAMERA_HDR_RATIO = 2.5f;
33 constexpr float HDR_WHITE = 1000.0f;
34 constexpr float DEFAULT_SCALER = HDR_WHITE / REFERENCE_WHITE;
35
CalScaler(const float & maxContentLightLevel)36 float CalScaler(const float& maxContentLightLevel)
37 {
38 if (ROSEN_EQ(maxContentLightLevel, REFERENCE_WHITE)) {
39 return DEFAULT_HDR_RATIO;
40 } else if (ROSEN_GE(maxContentLightLevel, CAMERA_WHITE_MIN) && ROSEN_LE(maxContentLightLevel, CAMERA_WHITE_MAX)) {
41 return CAMERA_HDR_RATIO;
42 } else if (ROSEN_LE(maxContentLightLevel, HDR_WHITE)) {
43 return HDR_WHITE / REFERENCE_WHITE;
44 } else {
45 return maxContentLightLevel / REFERENCE_WHITE;
46 }
47 }
48 }; // namespace
49
RSColorSpaceConvert()50 RSColorSpaceConvert::RSColorSpaceConvert()
51 {
52 handle_ = dlopen("libvideoprocessingengine.z.so", RTLD_LAZY);
53 if (handle_ == nullptr) {
54 RS_LOGW("[%{public}s]:load library failed, reason: %{public}s", __func__, dlerror());
55 return;
56 }
57 colorSpaceConvertDisplayCreate_ = reinterpret_cast<VPEColorSpaceConvertDisplayCreate>(
58 dlsym(handle_, "ColorSpaceConvertDisplayCreate"));
59 if (colorSpaceConvertDisplayCreate_ == nullptr) {
60 RS_LOGW("[%{public}s]:load func failed, reason: %{public}s", __func__, dlerror());
61 if (dlclose(handle_) != 0) {
62 ROSEN_LOGE("Could not close the handle. This indicates a leak. %{public}s", dlerror());
63 }
64 handle_ = nullptr;
65 return;
66 }
67 colorSpaceConvertDisplayDestroy_ = reinterpret_cast<VPEColorSpaceConvertDisplayDestroy>(
68 dlsym(handle_, "ColorSpaceConvertDisplayDestroy"));
69 if (colorSpaceConvertDisplayDestroy_ == nullptr) {
70 RS_LOGW("[%{public}s]:load func failed, reason: %{public}s", __func__, dlerror());
71 if (dlclose(handle_) != 0) {
72 ROSEN_LOGE("Could not close the handle. This indicates a leak. %{public}s", dlerror());
73 }
74 handle_ = nullptr;
75 return;
76 }
77 colorSpaceConvertDisplayHandle_ = colorSpaceConvertDisplayCreate_();
78 if (colorSpaceConvertDisplayHandle_ == nullptr) {
79 RS_LOGE("ColorSpaceConvertDisplayCreate failed, return nullptr");
80 if (dlclose(handle_) != 0) {
81 ROSEN_LOGE("Could not close the handle. This indicates a leak. %{public}s", dlerror());
82 }
83 handle_ = nullptr;
84 return;
85 }
86 colorSpaceConverterDisplay_ = static_cast<ColorSpaceConvertDisplayHandleImpl *>(
87 colorSpaceConvertDisplayHandle_)->obj;
88 }
89
~RSColorSpaceConvert()90 RSColorSpaceConvert::~RSColorSpaceConvert()
91 {
92 if (colorSpaceConvertDisplayHandle_) {
93 colorSpaceConvertDisplayDestroy_(colorSpaceConvertDisplayHandle_);
94 colorSpaceConvertDisplayHandle_ = nullptr;
95 }
96 if (handle_) {
97 if (dlclose(handle_) != 0) {
98 ROSEN_LOGE("Could not close the handle. This indicates a leak. %{public}s", dlerror());
99 }
100 handle_ = nullptr;
101 }
102 colorSpaceConvertDisplayCreate_ = nullptr;
103 colorSpaceConvertDisplayDestroy_ = nullptr;
104 colorSpaceConverterDisplay_ = nullptr;
105 }
106
Instance()107 RSColorSpaceConvert& RSColorSpaceConvert::Instance()
108 {
109 static RSColorSpaceConvert instance;
110 return instance;
111 }
112
ColorSpaceConvertor(std::shared_ptr<Drawing::ShaderEffect> inputShader,const sptr<SurfaceBuffer> & surfaceBuffer,Drawing::Paint & paint,GraphicColorGamut targetColorSpace,ScreenId screenId,uint32_t dynamicRangeMode)113 bool RSColorSpaceConvert::ColorSpaceConvertor(std::shared_ptr<Drawing::ShaderEffect> inputShader,
114 const sptr<SurfaceBuffer>& surfaceBuffer, Drawing::Paint& paint, GraphicColorGamut targetColorSpace,
115 ScreenId screenId, uint32_t dynamicRangeMode)
116 {
117 RS_LOGD("RSColorSpaceConvertor targetColorSpace:%{public}d. screenId:%{public}" PRIu64 ". \
118 dynamicRangeMode%{public}u", targetColorSpace, screenId, dynamicRangeMode);
119 VPEParameter parameter;
120
121 if (inputShader == nullptr) {
122 RS_LOGE("bhdr imageShader is nullptr.");
123 return false;
124 }
125
126 if (!SetColorSpaceConverterDisplayParameter(surfaceBuffer, parameter, targetColorSpace, screenId,
127 dynamicRangeMode)) {
128 return false;
129 }
130 if (dynamicRangeMode == DynamicRangeMode::STANDARD) {
131 parameter.disableHeadRoom = true;
132 }
133
134 std::shared_ptr<Drawing::ShaderEffect> outputShader;
135
136 if (colorSpaceConverterDisplay_ == nullptr) {
137 RS_LOGE("colorSpaceConverterDisplay_ is nullptr.");
138 return false;
139 }
140 auto convRet = colorSpaceConverterDisplay_->Process(inputShader, outputShader, parameter);
141 if (convRet != Media::VideoProcessingEngine::VPE_ALGO_ERR_OK) {
142 RS_LOGE("bhdr failed with %{public}u.", convRet);
143 return false;
144 }
145 if (outputShader == nullptr) {
146 RS_LOGE("bhdr outputShader is nullptr.");
147 return false;
148 }
149 paint.SetShaderEffect(outputShader);
150 return true;
151 }
152
SetColorSpaceConverterDisplayParameter(const sptr<SurfaceBuffer> & surfaceBuffer,VPEParameter & parameter,GraphicColorGamut targetColorSpace,ScreenId screenId,uint32_t dynamicRangeMode)153 bool RSColorSpaceConvert::SetColorSpaceConverterDisplayParameter(const sptr<SurfaceBuffer>& surfaceBuffer,
154 VPEParameter& parameter, GraphicColorGamut targetColorSpace, ScreenId screenId, uint32_t dynamicRangeMode)
155 {
156 using namespace HDIV;
157
158 GSError ret = MetadataHelper::GetColorSpaceInfo(surfaceBuffer, parameter.inputColorSpace.colorSpaceInfo);
159 if (ret != GSERROR_OK) {
160 RS_LOGE("bhdr GetColorSpaceInfo failed with %{public}u.", ret);
161 return false;
162 }
163 if (!ConvertColorGamutToSpaceInfo(targetColorSpace, parameter.outputColorSpace.colorSpaceInfo)) {
164 return false;
165 }
166 CM_HDR_Metadata_Type hdrMetadataType = CM_METADATA_NONE;
167 ret = MetadataHelper::GetHDRMetadataType(surfaceBuffer, hdrMetadataType);
168 if (ret != GSERROR_OK) {
169 RS_LOGD("bhdr GetHDRMetadataType failed with %{public}u.", ret);
170 }
171 parameter.inputColorSpace.metadataType = hdrMetadataType;
172 parameter.outputColorSpace.metadataType = hdrMetadataType;
173
174 ret = MetadataHelper::GetHDRStaticMetadata(surfaceBuffer, parameter.staticMetadata);
175 if (ret != GSERROR_OK) {
176 RS_LOGD("bhdr GetHDRStaticMetadata failed with %{public}u.", ret);
177 }
178
179 float scaler = DEFAULT_SCALER;
180 if (parameter.staticMetadata.size() != sizeof(HdrStaticMetadata)) {
181 RS_LOGD("bhdr parameter.staticMetadata size is invalid");
182 } else {
183 const auto& data = *reinterpret_cast<HdrStaticMetadata*>(parameter.staticMetadata.data());
184 scaler = CalScaler(data.cta861.maxContentLightLevel);
185 }
186
187 ret = MetadataHelper::GetHDRDynamicMetadata(surfaceBuffer, parameter.dynamicMetadata);
188 if (ret != GSERROR_OK) {
189 RS_LOGD("bhdr GetHDRDynamicMetadata failed with %{public}u.", ret);
190 }
191
192 // Set brightness to screen brightness when HDR Vivid, otherwise 500 nits
193 float sdrNits = RSLuminanceControl::Get().GetSdrDisplayNits(screenId);
194 float displayNits = RSLuminanceControl::Get().GetDisplayNits(screenId);
195 parameter.tmoNits = std::clamp(sdrNits * scaler, sdrNits, displayNits);
196 parameter.currentDisplayNits = displayNits;
197 parameter.sdrNits = sdrNits;
198 RS_LOGD("bhdr TmoNits:%{public}f. DisplayNits:%{public}f. SdrNits:%{public}f.", parameter.tmoNits,
199 parameter.currentDisplayNits, parameter.sdrNits);
200 return true;
201 }
202
ConvertColorGamutToSpaceInfo(const GraphicColorGamut & colorGamut,HDIV::CM_ColorSpaceInfo & colorSpaceInfo)203 bool RSColorSpaceConvert::ConvertColorGamutToSpaceInfo(const GraphicColorGamut& colorGamut,
204 HDIV::CM_ColorSpaceInfo& colorSpaceInfo)
205 {
206 using namespace HDIV;
207 static const std::map<GraphicColorGamut, CM_ColorSpaceType> RS_TO_COMMON_COLOR_SPACE_TYPE_MAP {
208 {GRAPHIC_COLOR_GAMUT_STANDARD_BT601, CM_BT601_EBU_FULL},
209 {GRAPHIC_COLOR_GAMUT_STANDARD_BT709, CM_BT709_FULL},
210 {GRAPHIC_COLOR_GAMUT_SRGB, CM_SRGB_FULL},
211 {GRAPHIC_COLOR_GAMUT_ADOBE_RGB, CM_ADOBERGB_FULL},
212 {GRAPHIC_COLOR_GAMUT_DISPLAY_P3, CM_P3_FULL},
213 {GRAPHIC_COLOR_GAMUT_BT2020, CM_DISPLAY_BT2020_SRGB},
214 {GRAPHIC_COLOR_GAMUT_BT2100_PQ, CM_BT2020_PQ_FULL},
215 {GRAPHIC_COLOR_GAMUT_BT2100_HLG, CM_BT2020_HLG_FULL},
216 {GRAPHIC_COLOR_GAMUT_DISPLAY_BT2020, CM_DISPLAY_BT2020_SRGB},
217 };
218
219 CM_ColorSpaceType colorSpaceType = CM_COLORSPACE_NONE;
220 if (RS_TO_COMMON_COLOR_SPACE_TYPE_MAP.find(colorGamut) != RS_TO_COMMON_COLOR_SPACE_TYPE_MAP.end()) {
221 colorSpaceType = RS_TO_COMMON_COLOR_SPACE_TYPE_MAP.at(colorGamut);
222 }
223
224 GSError ret = MetadataHelper::ConvertColorSpaceTypeToInfo(colorSpaceType, colorSpaceInfo);
225 if (ret != GSERROR_OK) {
226 RS_LOGE("bhdr ConvertColorSpaceTypeToInfo failed with %{public}u.", ret);
227 return false;
228 }
229
230 return true;
231 }
232
233 } // namespace Rosen
234 } // namespace OHOS
235