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 
16 #include "render/rs_blur_filter.h"
17 
18 #include "src/core/SkOpts.h"
19 
20 #include "common/rs_common_def.h"
21 #include "platform/common/rs_log.h"
22 #include "platform/common/rs_system_properties.h"
23 
24 
25 namespace OHOS {
26 namespace Rosen {
27 const bool KAWASE_BLUR_ENABLED = RSSystemProperties::GetKawaseEnabled();
28 const auto BLUR_TYPE = KAWASE_BLUR_ENABLED ? Drawing::ImageBlurType::KAWASE : Drawing::ImageBlurType::GAUSS;
RSBlurFilter(float blurRadiusX,float blurRadiusY)29 RSBlurFilter::RSBlurFilter(float blurRadiusX, float blurRadiusY) : RSDrawingFilterOriginal(
30     Drawing::ImageFilter::CreateBlurImageFilter(blurRadiusX, blurRadiusY, Drawing::TileMode::CLAMP, nullptr,
31         BLUR_TYPE)),
32     blurRadiusX_(blurRadiusX),
33     blurRadiusY_(blurRadiusY)
34 {
35     type_ = FilterType::BLUR;
36 
37     float blurRadiusXForHash = DecreasePrecision(blurRadiusX);
38     float blurRadiusYForHash = DecreasePrecision(blurRadiusY);
39     hash_ = SkOpts::hash(&type_, sizeof(type_), 0);
40     hash_ = SkOpts::hash(&blurRadiusXForHash, sizeof(blurRadiusXForHash), hash_);
41     hash_ = SkOpts::hash(&blurRadiusYForHash, sizeof(blurRadiusYForHash), hash_);
42 }
43 
44 RSBlurFilter::~RSBlurFilter() = default;
45 
GetBlurRadiusX()46 float RSBlurFilter::GetBlurRadiusX()
47 {
48     return blurRadiusX_;
49 }
50 
GetBlurRadiusY()51 float RSBlurFilter::GetBlurRadiusY()
52 {
53     return blurRadiusY_;
54 }
55 
GetDescription()56 std::string RSBlurFilter::GetDescription()
57 {
58     return "RSBlurFilter blur radius is " + std::to_string(blurRadiusX_) + " sigma";
59 }
60 
GetDetailedDescription()61 std::string RSBlurFilter::GetDetailedDescription()
62 {
63     return "RSBlurFilterBlur, radius: " + std::to_string(blurRadiusX_) + " sigma" +
64         ", greyCoef1: " + std::to_string(greyCoef_ == std::nullopt ? 0.0f : greyCoef_->x_) +
65         ", greyCoef2: " + std::to_string(greyCoef_ == std::nullopt ? 0.0f : greyCoef_->y_);
66 }
67 
IsValid() const68 bool RSBlurFilter::IsValid() const
69 {
70     constexpr float epsilon = 0.999f;
71     return blurRadiusX_ > epsilon || blurRadiusY_ > epsilon;
72 }
73 
Compose(const std::shared_ptr<RSDrawingFilterOriginal> & other) const74 std::shared_ptr<RSDrawingFilterOriginal> RSBlurFilter::Compose(
75     const std::shared_ptr<RSDrawingFilterOriginal>& other) const
76 {
77     std::shared_ptr<RSBlurFilter> result = std::make_shared<RSBlurFilter>(blurRadiusX_, blurRadiusY_);
78     result->imageFilter_ = Drawing::ImageFilter::CreateComposeImageFilter(imageFilter_, other->GetImageFilter());
79     auto otherHash = other->Hash();
80     result->hash_ = SkOpts::hash(&otherHash, sizeof(otherHash), hash_);
81     return result;
82 }
83 
Add(const std::shared_ptr<RSFilter> & rhs)84 std::shared_ptr<RSFilter> RSBlurFilter::Add(const std::shared_ptr<RSFilter>& rhs)
85 {
86     if ((rhs == nullptr) || (rhs->GetFilterType() != FilterType::BLUR)) {
87         return shared_from_this();
88     }
89     auto blurR = std::static_pointer_cast<RSBlurFilter>(rhs);
90     return std::make_shared<RSBlurFilter>(
91         blurRadiusX_ + blurR->GetBlurRadiusX(), blurRadiusY_ + blurR->GetBlurRadiusY());
92 }
93 
Sub(const std::shared_ptr<RSFilter> & rhs)94 std::shared_ptr<RSFilter> RSBlurFilter::Sub(const std::shared_ptr<RSFilter>& rhs)
95 {
96     if ((rhs == nullptr) || (rhs->GetFilterType() != FilterType::BLUR)) {
97         return shared_from_this();
98     }
99     auto blurR = std::static_pointer_cast<RSBlurFilter>(rhs);
100     return std::make_shared<RSBlurFilter>(
101         blurRadiusX_ - blurR->GetBlurRadiusX(), blurRadiusY_ - blurR->GetBlurRadiusY());
102 }
103 
Multiply(float rhs)104 std::shared_ptr<RSFilter> RSBlurFilter::Multiply(float rhs)
105 {
106     return std::make_shared<RSBlurFilter>(blurRadiusX_ * rhs, blurRadiusY_ * rhs);
107 }
108 
Negate()109 std::shared_ptr<RSFilter> RSBlurFilter::Negate()
110 {
111     return std::make_shared<RSBlurFilter>(-blurRadiusX_, -blurRadiusY_);
112 }
113 
IsNearEqual(const std::shared_ptr<RSFilter> & other,float threshold) const114 bool RSBlurFilter::IsNearEqual(const std::shared_ptr<RSFilter>& other, float threshold) const
115 {
116     auto otherBlurFilter = std::static_pointer_cast<RSBlurFilter>(other);
117     if (otherBlurFilter == nullptr) {
118         ROSEN_LOGE("RSBlurFilter::IsNearEqual: the types of filters are different.");
119         return true;
120     }
121     return ROSEN_EQ(blurRadiusX_, otherBlurFilter->GetBlurRadiusX(), threshold) &&
122            ROSEN_EQ(blurRadiusY_, otherBlurFilter->GetBlurRadiusY(), threshold);
123 }
124 
IsNearZero(float threshold) const125 bool RSBlurFilter::IsNearZero(float threshold) const
126 {
127     return ROSEN_EQ(blurRadiusX_, 0.0f, threshold) && ROSEN_EQ(blurRadiusY_, 0.0f, threshold);
128 }
129 
IsEqual(const std::shared_ptr<RSFilter> & other) const130 bool RSBlurFilter::IsEqual(const std::shared_ptr<RSFilter>& other) const
131 {
132     auto otherBlurFilter = std::static_pointer_cast<RSBlurFilter>(other);
133     if (otherBlurFilter == nullptr) {
134         ROSEN_LOGE("RSBlurFilter::IsEqual: the types of filters are different.");
135         return true;
136     }
137     return ROSEN_EQ(blurRadiusX_, otherBlurFilter->GetBlurRadiusX()) &&
138            ROSEN_EQ(blurRadiusY_, otherBlurFilter->GetBlurRadiusY());
139 }
140 
IsEqualZero() const141 bool RSBlurFilter::IsEqualZero() const
142 {
143     return ROSEN_EQ(blurRadiusX_, 0.0f) && ROSEN_EQ(blurRadiusY_, 0.0f);
144 }
145 
DrawImageRect(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const Drawing::Rect & src,const Drawing::Rect & dst) const146 void RSBlurFilter::DrawImageRect(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
147     const Drawing::Rect& src, const Drawing::Rect& dst) const
148 {
149     auto brush = GetBrush();
150     std::shared_ptr<Drawing::Image> greyImage = image;
151     if (greyCoef_.has_value()) {
152         greyImage = RSPropertiesPainter::DrawGreyAdjustment(canvas, image, greyCoef_.value());
153     }
154     if (greyImage == nullptr) {
155         greyImage = image;
156     }
157     // if kawase blur failed, use gauss blur
158     static bool DDGR_ENABLED = RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR;
159     KawaseParameter param = KawaseParameter(src, dst, blurRadiusX_, nullptr, brush.GetColor().GetAlphaF());
160     if (!DDGR_ENABLED && KAWASE_BLUR_ENABLED &&
161         KawaseBlurFilter::GetKawaseBlurFilter()->ApplyKawaseBlur(canvas, greyImage, param)) {
162         return;
163     }
164     canvas.AttachBrush(brush);
165     canvas.DrawImageRect(*greyImage, src, dst, Drawing::SamplingOptions());
166     canvas.DetachBrush();
167 }
168 
SetGreyCoef(const std::optional<Vector2f> & greyCoef)169 void RSBlurFilter::SetGreyCoef(const std::optional<Vector2f>& greyCoef)
170 {
171     greyCoef_ = greyCoef;
172 }
173 
CanSkipFrame() const174 bool RSBlurFilter::CanSkipFrame() const
175 {
176     constexpr float HEAVY_BLUR_THRESHOLD = 25.0f;
177     return blurRadiusX_ > HEAVY_BLUR_THRESHOLD && blurRadiusY_ > HEAVY_BLUR_THRESHOLD;
178 };
179 } // namespace Rosen
180 } // namespace OHOS
181