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