1 /*
2 * Copyright (c) 2021-2023 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_material_filter.h"
16
17 #include <unordered_map>
18
19 #include "src/core/SkOpts.h"
20
21 #include "common/rs_common_def.h"
22 #include "common/rs_optional_trace.h"
23 #include "pipeline/rs_paint_filter_canvas.h"
24 #include "platform/common/rs_log.h"
25 #include "property/rs_properties_painter.h"
26 #include "platform/common/rs_system_properties.h"
27
28 #if defined(NEW_SKIA)
29 #include "include/effects/SkImageFilters.h"
30 #include "include/core/SkTileMode.h"
31 #else
32 #include "include/effects/SkBlurImageFilter.h"
33 #endif
34
35 namespace OHOS {
36 namespace Rosen {
37 namespace {
38 // style to MaterialParam map
39 static const std::unordered_map<MATERIAL_BLUR_STYLE, MaterialParam> MATERIAL_PARAM {
40 // card blur params
41 { STYLE_CARD_THIN_LIGHT, { 23.0f, 1.05, 1.05, RSColor(0xFFFFFF33) } },
42 { STYLE_CARD_LIGHT, { 50.0f, 1.8, 1.0, RSColor(0xFAFAFA99) } },
43 { STYLE_CARD_THICK_LIGHT, { 57.0f, 1.2, 1.1, RSColor(0xFFFFFF8C) } },
44 { STYLE_CARD_THIN_DARK, { 75.0f, 1.35, 1.0, RSColor(0x1A1A1A6B) } },
45 { STYLE_CARD_DARK, { 50.0f, 2.15, 1.0, RSColor(0x1F1F1FD1) } },
46 { STYLE_CARD_THICK_DARK, { 75.0f, 2.15, 1.0, RSColor(0x1F1F1FD1) } },
47 // background blur params
48 { STYLE_BACKGROUND_SMALL_LIGHT, { 23.0f, 1.05, 1.0, RSColor(0x80808033) } },
49 { STYLE_BACKGROUND_MEDIUM_LIGHT, { 29.0f, 1.1, 1.0, RSColor(0x80808033) } },
50 { STYLE_BACKGROUND_LARGE_LIGHT, { 57.0f, 1.2, 1.0, RSColor(0x80808033) } },
51 { STYLE_BACKGROUND_XLARGE_LIGHT, { 120.0f, 1.3, 1.0, RSColor(0x6666664C) } },
52 { STYLE_BACKGROUND_SMALL_DARK, { 15.0f, 1.1, 1.0, RSColor(0x0D0D0D80) } },
53 { STYLE_BACKGROUND_MEDIUM_DARK, { 55.0f, 1.15, 1.0, RSColor(0x0D0D0D80) } },
54 { STYLE_BACKGROUND_LARGE_DARK, { 75.0f, 1.5, 1.0, RSColor(0x0D0D0D80) } },
55 { STYLE_BACKGROUND_XLARGE_DARK, { 130.0f, 1.3, 1.0, RSColor(0x0D0D0D80) } },
56 };
57
58 static const std::unordered_map<MATERIAL_BLUR_STYLE, MaterialParam> KAWASE_MATERIAL_PARAM {
59 // card blur params
60 { STYLE_CARD_THIN_LIGHT, { 23.0f, 1.05, 1.05, RSColor(0xFFFFFF33) } },
61 { STYLE_CARD_LIGHT, { 50.0f, 1.8, 1.0, RSColor(0xFAFAFA99) } },
62 { STYLE_CARD_THICK_LIGHT, { 57.0f, 1.2, 1.1, RSColor(0xFFFFFF8C) } },
63 { STYLE_CARD_THIN_DARK, { 75.0f, 1.35, 1.0, RSColor(0x1A1A1A6B) } },
64 { STYLE_CARD_DARK, { 50.0f, 2.15, 1.0, RSColor(0x1F1F1FD1) } },
65 { STYLE_CARD_THICK_DARK, { 75.0f, 2.15, 1.0, RSColor(0x1F1F1FD1) } },
66 // background blur params
67 { STYLE_BACKGROUND_SMALL_LIGHT, { 12.0f, 1.05, 1.0, RSColor(0x80808033) } },
68 { STYLE_BACKGROUND_MEDIUM_LIGHT, { 29.0f, 1.1, 1.0, RSColor(0x80808033) } },
69 { STYLE_BACKGROUND_LARGE_LIGHT, { 45.0f, 1.2, 1.0, RSColor(0x80808033) } },
70 { STYLE_BACKGROUND_XLARGE_LIGHT, { 120.0f, 1.3, 1.0, RSColor(0x6666664C) } },
71 { STYLE_BACKGROUND_SMALL_DARK, { 15.0f, 1.1, 1.0, RSColor(0x0D0D0D80) } },
72 { STYLE_BACKGROUND_MEDIUM_DARK, { 55.0f, 1.15, 1.0, RSColor(0x0D0D0D80) } },
73 { STYLE_BACKGROUND_LARGE_DARK, { 75.0f, 1.5, 1.0, RSColor(0x0D0D0D80) } },
74 { STYLE_BACKGROUND_XLARGE_DARK, { 130.0f, 1.3, 1.0, RSColor(0x0D0D0D80) } },
75 };
76 } // namespace
77
78 const bool KAWASE_BLUR_ENABLED = RSSystemProperties::GetKawaseEnabled();
79 const bool HPS_BLUR_ENABLED = RSSystemProperties::GetHpsBlurEnabled();
80
RSMaterialFilter(int style,float dipScale,BLUR_COLOR_MODE mode,float ratio)81 RSMaterialFilter::RSMaterialFilter(int style, float dipScale, BLUR_COLOR_MODE mode, float ratio)
82 : RSDrawingFilterOriginal(nullptr), colorMode_(mode)
83 {
84 imageFilter_ = RSMaterialFilter::CreateMaterialStyle(static_cast<MATERIAL_BLUR_STYLE>(style), dipScale, ratio);
85 type_ = FilterType::MATERIAL;
86
87 hash_ = SkOpts::hash(&type_, sizeof(type_), 0);
88 hash_ = SkOpts::hash(&style, sizeof(style), hash_);
89 hash_ = SkOpts::hash(&colorMode_, sizeof(colorMode_), hash_);
90 hash_ = SkOpts::hash(&ratio, sizeof(ratio), hash_);
91 }
92
RSMaterialFilter(MaterialParam materialParam,BLUR_COLOR_MODE mode)93 RSMaterialFilter::RSMaterialFilter(MaterialParam materialParam, BLUR_COLOR_MODE mode)
94 : RSDrawingFilterOriginal(nullptr), colorMode_(mode),
95 radius_(materialParam.radius), saturation_(materialParam.saturation),
96 brightness_(materialParam.brightness), maskColor_(materialParam.maskColor)
97 {
98 imageFilter_ = RSMaterialFilter::CreateMaterialFilter(
99 materialParam.radius, materialParam.saturation, materialParam.brightness);
100 type_ = FilterType::MATERIAL;
101 if (colorMode_ == FASTAVERAGE) {
102 colorMode_ = AVERAGE;
103 }
104
105 float radiusForHash = DecreasePrecision(radius_);
106 float saturationForHash = DecreasePrecision(saturation_);
107 float brightnessForHash = DecreasePrecision(brightness_);
108 hash_ = SkOpts::hash(&type_, sizeof(type_), 0);
109 hash_ = SkOpts::hash(&radiusForHash, sizeof(radiusForHash), hash_);
110 hash_ = SkOpts::hash(&saturationForHash, sizeof(saturationForHash), hash_);
111 hash_ = SkOpts::hash(&brightnessForHash, sizeof(brightnessForHash), hash_);
112 hash_ = SkOpts::hash(&maskColor_, sizeof(maskColor_), hash_);
113 hash_ = SkOpts::hash(&colorMode_, sizeof(colorMode_), hash_);
114 }
115
116 RSMaterialFilter::~RSMaterialFilter() = default;
117
RadiusVp2Sigma(float radiusVp,float dipScale)118 float RSMaterialFilter::RadiusVp2Sigma(float radiusVp, float dipScale)
119 {
120 float radiusPx = radiusVp * dipScale;
121 return radiusPx > 0.0f ? BLUR_SIGMA_SCALE * radiusPx + 0.5f : 0.0f;
122 }
123
GetDescription()124 std::string RSMaterialFilter::GetDescription()
125 {
126 return "RSMaterialFilter blur radius is " + std::to_string(radius_) + " sigma";
127 }
128
GetDetailedDescription()129 std::string RSMaterialFilter::GetDetailedDescription()
130 {
131 char maskColorStr[UINT8_MAX] = { 0 };
132 auto ret = memset_s(maskColorStr, UINT8_MAX, 0, UINT8_MAX);
133 if (ret != EOK) {
134 return "Failed to memset_s for maskColorStr, ret=" + std::to_string(ret);
135 }
136 if (sprintf_s(maskColorStr, UINT8_MAX, "%08X", maskColor_.AsArgbInt()) != -1) {
137 return "RSMaterialFilterBlur, radius: " + std::to_string(radius_) + " sigma" +
138 ", saturation: " + std::to_string(saturation_) + ", brightness: " + std::to_string(brightness_) +
139 ", greyCoef1: " + std::to_string(greyCoef_ == std::nullopt ? 0.0f : greyCoef_->x_) +
140 ", greyCoef2: " + std::to_string(greyCoef_ == std::nullopt ? 0.0f : greyCoef_->y_) +
141 ", color: " + maskColorStr + ", colorMode: " + std::to_string(colorMode_);
142 };
143 return "RSMaterialFilterBlur, maskColorStr failed";
144 }
145
Compose(const std::shared_ptr<RSDrawingFilterOriginal> & other) const146 std::shared_ptr<RSDrawingFilterOriginal> RSMaterialFilter::Compose(
147 const std::shared_ptr<RSDrawingFilterOriginal>& other) const
148 {
149 if (other == nullptr) {
150 return nullptr;
151 }
152 MaterialParam materialParam = {radius_, saturation_, brightness_, maskColor_};
153 std::shared_ptr<RSMaterialFilter> result = std::make_shared<RSMaterialFilter>(materialParam, colorMode_);
154 result->imageFilter_ = Drawing::ImageFilter::CreateComposeImageFilter(imageFilter_, other->GetImageFilter());
155 auto otherHash = other->Hash();
156 result->hash_ = SkOpts::hash(&otherHash, sizeof(otherHash), hash_);
157 return result;
158 }
159
GetColorFilter(float sat,float brightness)160 std::shared_ptr<Drawing::ColorFilter> RSMaterialFilter::GetColorFilter(float sat, float brightness)
161 {
162 float normalizedDegree = brightness - 1.0;
163 const float brightnessMat[] = {
164 1.000000f, 0.000000f, 0.000000f, 0.000000f, normalizedDegree,
165 0.000000f, 1.000000f, 0.000000f, 0.000000f, normalizedDegree,
166 0.000000f, 0.000000f, 1.000000f, 0.000000f, normalizedDegree,
167 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
168 };
169
170 Drawing::ColorMatrix cm;
171 cm.SetSaturation(sat);
172 float cmArray[Drawing::ColorMatrix::MATRIX_SIZE];
173 cm.GetArray(cmArray);
174 std::shared_ptr<Drawing::ColorFilter> filterCompose =
175 Drawing::ColorFilter::CreateComposeColorFilter(cmArray, brightnessMat);
176 return filterCompose;
177 }
178
CreateMaterialFilter(float radius,float sat,float brightness)179 std::shared_ptr<Drawing::ImageFilter> RSMaterialFilter::CreateMaterialFilter(float radius, float sat, float brightness)
180 {
181 colorFilter_ = GetColorFilter(sat, brightness);
182 auto blurType = KAWASE_BLUR_ENABLED ? Drawing::ImageBlurType::KAWASE : Drawing::ImageBlurType::GAUSS;
183 if (colorFilter_) {
184 return Drawing::ImageFilter::CreateColorBlurImageFilter(*colorFilter_, radius, radius, blurType);
185 }
186 return Drawing::ImageFilter::CreateBlurImageFilter(radius, radius, Drawing::TileMode::CLAMP, nullptr, blurType);
187 }
188
CreateMaterialStyle(MATERIAL_BLUR_STYLE style,float dipScale,float ratio)189 std::shared_ptr<Drawing::ImageFilter> RSMaterialFilter::CreateMaterialStyle(
190 MATERIAL_BLUR_STYLE style, float dipScale, float ratio)
191 {
192 const auto& materialParams = KAWASE_BLUR_ENABLED ? KAWASE_MATERIAL_PARAM : MATERIAL_PARAM;
193 if (auto iter = materialParams.find(style); iter != materialParams.end()) {
194 const auto& materialParam = iter->second;
195 maskColor_ = RSColor(materialParam.maskColor.AsRgbaInt());
196 maskColor_.MultiplyAlpha(ratio);
197 radius_ = RSMaterialFilter::RadiusVp2Sigma(materialParam.radius, dipScale) * ratio;
198 saturation_ = (materialParam.saturation - 1) * ratio + 1.0;
199 brightness_ = (materialParam.brightness - 1) * ratio + 1.0;
200 return RSMaterialFilter::CreateMaterialFilter(radius_, saturation_, brightness_);
201 }
202 return nullptr;
203 }
204
PreProcess(std::shared_ptr<Drawing::Image> imageSnapshot)205 void RSMaterialFilter::PreProcess(std::shared_ptr<Drawing::Image> imageSnapshot)
206 {
207 if (colorMode_ == AVERAGE && imageSnapshot != nullptr) {
208 // update maskColor while persevere alpha
209 auto colorPicker = RSPropertiesPainter::CalcAverageColor(imageSnapshot);
210 maskColor_ = RSColor(Drawing::Color::ColorQuadGetR(colorPicker), Drawing::Color::ColorQuadGetG(colorPicker),
211 Drawing::Color::ColorQuadGetB(colorPicker), maskColor_.GetAlpha());
212 }
213 }
214
PostProcess(Drawing::Canvas & canvas)215 void RSMaterialFilter::PostProcess(Drawing::Canvas& canvas)
216 {
217 Drawing::Brush brush;
218 brush.SetColor(maskColor_.AsArgbInt());
219 canvas.DrawBackground(brush);
220 }
221
TransformFilter(float fraction) const222 std::shared_ptr<RSFilter> RSMaterialFilter::TransformFilter(float fraction) const
223 {
224 MaterialParam materialParam;
225 materialParam.radius = radius_ * fraction;
226 materialParam.saturation = (saturation_ - 1) * fraction + 1.0;
227 materialParam.brightness = (brightness_ - 1) * fraction + 1.0;
228 materialParam.maskColor = RSColor(maskColor_.GetRed(), maskColor_.GetGreen(),
229 maskColor_.GetBlue(), maskColor_.GetAlpha() * fraction);
230 return std::make_shared<RSMaterialFilter>(materialParam, colorMode_);
231 }
232
IsValid() const233 bool RSMaterialFilter::IsValid() const
234 {
235 constexpr float epsilon = 0.999f;
236 return radius_ > epsilon;
237 }
238
Add(const std::shared_ptr<RSFilter> & rhs)239 std::shared_ptr<RSFilter> RSMaterialFilter::Add(const std::shared_ptr<RSFilter>& rhs)
240 {
241 if ((rhs == nullptr) || (rhs->GetFilterType() != FilterType::MATERIAL)) {
242 return shared_from_this();
243 }
244 auto materialR = std::static_pointer_cast<RSMaterialFilter>(rhs);
245
246 MaterialParam materialParam;
247 materialParam.radius = radius_ + materialR->radius_;
248 materialParam.saturation = saturation_ + materialR->saturation_;
249 materialParam.brightness = brightness_ + materialR->brightness_;
250 materialParam.maskColor = maskColor_ + materialR->maskColor_;
251 return std::make_shared<RSMaterialFilter>(materialParam, materialR->colorMode_);
252 }
253
Sub(const std::shared_ptr<RSFilter> & rhs)254 std::shared_ptr<RSFilter> RSMaterialFilter::Sub(const std::shared_ptr<RSFilter>& rhs)
255 {
256 if ((rhs == nullptr) || (rhs->GetFilterType() != FilterType::MATERIAL)) {
257 return shared_from_this();
258 }
259 auto materialR = std::static_pointer_cast<RSMaterialFilter>(rhs);
260 MaterialParam materialParam;
261 materialParam.radius = radius_ - materialR->radius_;
262 materialParam.saturation = saturation_ - materialR->saturation_;
263 materialParam.brightness = brightness_ - materialR->brightness_;
264 materialParam.maskColor = maskColor_ - materialR->maskColor_;
265 return std::make_shared<RSMaterialFilter>(materialParam, materialR->colorMode_);
266 }
267
Multiply(float rhs)268 std::shared_ptr<RSFilter> RSMaterialFilter::Multiply(float rhs)
269 {
270 MaterialParam materialParam;
271 materialParam.radius = radius_ * rhs;
272 materialParam.saturation = saturation_ * rhs;
273 materialParam.brightness = brightness_ * rhs;
274 materialParam.maskColor = maskColor_ * rhs;
275 return std::make_shared<RSMaterialFilter>(materialParam, colorMode_);
276 }
277
Negate()278 std::shared_ptr<RSFilter> RSMaterialFilter::Negate()
279 {
280 MaterialParam materialParam;
281 materialParam.radius = -radius_;
282 materialParam.saturation = -saturation_;
283 materialParam.brightness = -brightness_;
284 materialParam.maskColor = RSColor(0x00000000) - maskColor_;
285 return std::make_shared<RSMaterialFilter>(materialParam, colorMode_);
286 }
287
DrawImageRect(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const Drawing::Rect & src,const Drawing::Rect & dst) const288 void RSMaterialFilter::DrawImageRect(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
289 const Drawing::Rect& src, const Drawing::Rect& dst) const
290 {
291 auto brush = GetBrush();
292 // if kawase blur failed, use gauss blur
293 std::shared_ptr<Drawing::Image> greyImage = image;
294 if (greyCoef_.has_value()) {
295 greyImage = RSPropertiesPainter::DrawGreyAdjustment(canvas, image, greyCoef_.value());
296 }
297 if (greyImage == nullptr) {
298 greyImage = image;
299 }
300
301 // if hps blur failed, use kawase blur
302 Drawing::HpsBlurParameter hpsParam = Drawing::HpsBlurParameter(src, dst, GetRadius(), saturation_, brightness_);
303 if (HPS_BLUR_ENABLED &&
304 HpsBlurFilter::GetHpsBlurFilter().ApplyHpsBlur(canvas, greyImage, hpsParam, brush.GetColor().GetAlphaF())) {
305 RS_OPTIONAL_TRACE_NAME("ApplyHPSBlur " + std::to_string(GetRadius()));
306 return;
307 }
308
309 static bool DDGR_ENABLED = RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR;
310 KawaseParameter param = KawaseParameter(src, dst, radius_, colorFilter_, brush.GetColor().GetAlphaF());
311 if (!DDGR_ENABLED && KAWASE_BLUR_ENABLED &&
312 KawaseBlurFilter::GetKawaseBlurFilter()->ApplyKawaseBlur(canvas, greyImage, param)) {
313 return;
314 }
315 canvas.AttachBrush(brush);
316 canvas.DrawImageRect(*greyImage, src, dst, Drawing::SamplingOptions());
317 canvas.DetachBrush();
318 }
319
SetGreyCoef(const std::optional<Vector2f> & greyCoef)320 void RSMaterialFilter::SetGreyCoef(const std::optional<Vector2f>& greyCoef)
321 {
322 greyCoef_ = greyCoef;
323 }
324
GetRadius() const325 float RSMaterialFilter::GetRadius() const
326 {
327 return radius_;
328 }
329
GetSaturation() const330 float RSMaterialFilter::GetSaturation() const
331 {
332 return saturation_;
333 }
334
GetBrightness() const335 float RSMaterialFilter::GetBrightness() const
336 {
337 return brightness_;
338 }
339
GetMaskColor() const340 RSColor RSMaterialFilter::GetMaskColor() const
341 {
342 return maskColor_;
343 }
344
GetColorMode() const345 BLUR_COLOR_MODE RSMaterialFilter::GetColorMode() const
346 {
347 return colorMode_;
348 }
349
CanSkipFrame() const350 bool RSMaterialFilter::CanSkipFrame() const
351 {
352 constexpr float HEAVY_BLUR_THRESHOLD = 25.0f;
353 return radius_ > HEAVY_BLUR_THRESHOLD;
354 };
355
IsNearEqual(const std::shared_ptr<RSFilter> & other,float threshold) const356 bool RSMaterialFilter::IsNearEqual(const std::shared_ptr<RSFilter>& other, float threshold) const
357 {
358 auto otherMaterialFilter = std::static_pointer_cast<RSMaterialFilter>(other);
359 if (otherMaterialFilter == nullptr) {
360 ROSEN_LOGE("RSMaterialFilter::IsNearEqual: the types of filters are different.");
361 return true;
362 }
363 return ROSEN_EQ(radius_, otherMaterialFilter->radius_, 1.0f) &&
364 ROSEN_EQ(saturation_, otherMaterialFilter->saturation_, threshold) &&
365 ROSEN_EQ(brightness_, otherMaterialFilter->brightness_, threshold) &&
366 maskColor_.IsNearEqual(otherMaterialFilter->maskColor_, 0);
367 }
368
IsNearZero(float threshold) const369 bool RSMaterialFilter::IsNearZero(float threshold) const
370 {
371 return ROSEN_EQ(radius_, 0.0f, threshold);
372 }
373
IsEqual(const std::shared_ptr<RSFilter> & other) const374 bool RSMaterialFilter::IsEqual(const std::shared_ptr<RSFilter>& other) const
375 {
376 auto otherMaterialFilter = std::static_pointer_cast<RSMaterialFilter>(other);
377 if (otherMaterialFilter == nullptr) {
378 ROSEN_LOGE("RSMaterialFilter::IsEqual: the types of filters are different.");
379 return true;
380 }
381 return ROSEN_EQ(radius_, otherMaterialFilter->radius_, 1.0f) &&
382 ROSEN_EQ(saturation_, otherMaterialFilter->saturation_) &&
383 ROSEN_EQ(brightness_, otherMaterialFilter->brightness_) &&
384 maskColor_.IsNearEqual(otherMaterialFilter->maskColor_, 0);
385 }
386
IsEqualZero() const387 bool RSMaterialFilter::IsEqualZero() const
388 {
389 return ROSEN_EQ(radius_, 0.0f);
390 }
391 } // namespace Rosen
392 } // namespace OHOS
393