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