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