• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-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_kawase_blur.h"
17 #include "platform/common/rs_log.h"
18 #include "platform/common/rs_system_properties.h"
19 #include "common/rs_optional_trace.h"
20 
21 namespace OHOS {
22 namespace Rosen {
23 #ifndef USE_ROSEN_DRAWING
KawaseBlurFilter()24 KawaseBlurFilter::KawaseBlurFilter()
25 {
26     SkString blurString(R"(
27         uniform shader imageInput;
28         uniform float2 in_blurOffset;
29         uniform float2 in_maxSizeXY;
30 
31         half4 main(float2 xy) {
32             half4 c = imageInput.eval(xy);
33             c += imageInput.eval(float2(clamp(in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
34                                         clamp(in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
35             c += imageInput.eval(float2(clamp(in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
36                                         clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
37             c += imageInput.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
38                                         clamp(in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
39             c += imageInput.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
40                                         clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
41             return half4(c.rgb * 0.2, 1.0);
42         }
43     )");
44 
45     SkString mixString(R"(
46         uniform shader blurredInput;
47         uniform shader originalInput;
48         uniform float mixFactor;
49         half4 main(float2 xy) {
50             return half4(mix(originalInput.eval(xy), blurredInput.eval(xy), mixFactor));
51         }
52     )");
53 
54     auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString);
55     if (!blurEffect) {
56         ROSEN_LOGE("KawaseBlurFilter::RuntimeShader blurEffect error: %s\n", error.c_str());
57         return;
58     }
59     blurEffect_ = std::move(blurEffect);
60 
61     auto [mixEffect, error2] = SkRuntimeEffect::MakeForShader(mixString);
62     if (!mixEffect) {
63         ROSEN_LOGE("KawaseBlurFilter::RuntimeShader mixEffect error: %s\n", error2.c_str());
64         return;
65     }
66     mixEffect_ = std::move(mixEffect);
67 }
68 
69 KawaseBlurFilter::~KawaseBlurFilter() = default;
70 
GetShaderTransform(const SkCanvas * canvas,const SkRect & blurRect,float scale)71 SkMatrix KawaseBlurFilter::GetShaderTransform(const SkCanvas* canvas, const SkRect& blurRect, float scale)
72 {
73     auto matrix = SkMatrix::Scale(scale, scale);
74     matrix.postConcat(SkMatrix::Translate(blurRect.fLeft, blurRect.fTop));
75     return matrix;
76 }
77 
ApplyKawaseBlur(SkCanvas & canvas,const sk_sp<SkImage> & image,const KawaseParameter & param)78 bool KawaseBlurFilter::ApplyKawaseBlur(SkCanvas& canvas, const sk_sp<SkImage>& image, const KawaseParameter& param)
79 {
80     auto src = param.src;
81     auto dst = param.dst;
82     int inputRadius = param.radius;
83     if (inputRadius <= 0) {
84         SkPaint paint;
85         if (param.colorFilter) {
86             paint.setColorFilter(param.colorFilter);
87         }
88         SkMatrix inputMatrix = SkMatrix::Translate(-src.fLeft, -src.fTop);
89         inputMatrix.postConcat(SkMatrix::Translate(dst.fLeft, dst.fTop));
90         SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone);
91         const auto inputShader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, &inputMatrix);
92         paint.setShader(inputShader);
93         canvas.drawRect(dst, paint);
94         return true;
95     }
96     if (!blurEffect_ || !mixEffect_) {
97         return false;
98     }
99     ComputeRadiusAndScale(param.radius);
100     RS_OPTIONAL_TRACE_BEGIN("ApplyKawaseBlur " + GetDescription());
101     int maxPasses = supportLargeRadius ? kMaxPassesLargeRadius : kMaxPasses;
102     float dilatedConvolutionFactor = supportLargeRadius ? kDilatedConvolutionLargeRadius : kDilatedConvolution;
103     float tmpRadius = static_cast<float>(blurRadius_) / dilatedConvolutionFactor;
104     int numberOfPasses = std::min(maxPasses, std::max(static_cast<int>(ceil(tmpRadius)), 1)); // 1 : min pass num
105     float radiusByPasses = tmpRadius / numberOfPasses;
106     SkImageInfo scaledInfo = image->imageInfo().makeWH(std::ceil(dst.width() * blurScale_),
107         std::ceil(dst.height() * blurScale_));
108     SkMatrix blurMatrix = SkMatrix::Translate(-src.fLeft, -src.fTop);
109     blurMatrix.postScale(blurScale_, blurScale_);
110     SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone);
111     SkRuntimeShaderBuilder blurBuilder(blurEffect_);
112     blurBuilder.child("imageInput") = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix);
113     blurBuilder.uniform("in_blurOffset") = SkV2{radiusByPasses * blurScale_, radiusByPasses * blurScale_};
114     blurBuilder.uniform("in_maxSizeXY") = SkV2{dst.width() * blurScale_, dst.height() * blurScale_};
115     sk_sp<SkImage> tmpBlur(blurBuilder.makeImage(canvas.recordingContext(), nullptr, scaledInfo, false));
116     // And now we'll build our chain of scaled blur stages
117     for (auto i = 1; i < numberOfPasses; i++) {
118         const float stepScale = static_cast<float>(i) * blurScale_;
119         blurBuilder.child("imageInput") = tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
120         blurBuilder.uniform("in_blurOffset") = SkV2{radiusByPasses * stepScale, radiusByPasses * stepScale};
121         blurBuilder.uniform("in_maxSizeXY") = SkV2{dst.width() * blurScale_, dst.height() * blurScale_};
122         tmpBlur = blurBuilder.makeImage(canvas.recordingContext(), nullptr, scaledInfo, false);
123     }
124     RS_OPTIONAL_TRACE_END();
125     return ApplyBlur(canvas, image, tmpBlur, param);
126 }
127 
ApplyBlur(SkCanvas & canvas,const sk_sp<SkImage> & image,const sk_sp<SkImage> & blurImage,const KawaseParameter & param) const128 bool KawaseBlurFilter::ApplyBlur(SkCanvas& canvas, const sk_sp<SkImage>& image, const sk_sp<SkImage>& blurImage,
129     const KawaseParameter& param) const
130 {
131     auto src = param.src;
132     auto dst = param.dst;
133     float invBlurScale = 1.0f / blurScale_;
134     SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone);
135     SkImageInfo scaledInfo = image->imageInfo().makeWH(std::ceil(dst.width() * blurScale_),
136         std::ceil(dst.height() * blurScale_));
137     const auto blurMatrix = GetShaderTransform(&canvas, dst, invBlurScale);
138     const auto blurShader = blurImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, &blurMatrix);
139     SkPaint paint;
140     paint.setAlphaf(param.alpha);
141     if (param.colorFilter) {
142         paint.setColorFilter(param.colorFilter);
143     }
144     if (blurRadius_ < kMaxCrossFadeRadius) {
145         SkMatrix inputMatrix = SkMatrix::Translate(-src.fLeft, -src.fTop);
146         inputMatrix.postConcat(SkMatrix::Translate(dst.fLeft, dst.fTop));
147         SkRuntimeShaderBuilder mixBuilder(mixEffect_);
148         mixBuilder.child("blurredInput") = blurShader;
149         mixBuilder.child("originalInput") = image->makeShader(
150             SkTileMode::kClamp, SkTileMode::kClamp, linear, inputMatrix);
151         mixBuilder.uniform("mixFactor") = std::min(1.0f, blurRadius_ * 1.f / kMaxCrossFadeRadius);
152         paint.setShader(mixBuilder.makeShader(nullptr, true));
153     } else {
154         paint.setShader(blurShader);
155     }
156     canvas.drawRect(dst, paint);
157     return true;
158 }
159 
ComputeRadiusAndScale(int radius)160 void KawaseBlurFilter::ComputeRadiusAndScale(int radius)
161 {
162     static constexpr int noiseFactor = 3; // 3 : smooth the radius change
163     blurRadius_ = radius * 4 / noiseFactor * noiseFactor; // 4 : scale between gauss radius and kawase
164     AdjustRadiusAndScale();
165 }
166 
AdjustRadiusAndScale()167 void KawaseBlurFilter::AdjustRadiusAndScale()
168 {
169     static constexpr int radiusStep1 = 50; // 50 : radius step1
170     static constexpr int radiusStep2 = 150; // 150 : radius step2
171     static constexpr int radiusStep3 = 480; // 480 : radius step3
172     static constexpr float scaleFactor1 = 0.25f; // 0.25 : downSample scale for step1
173     static constexpr float scaleFactor2 = 0.125f; // 0.125 : downSample scale for step2
174     static constexpr float scaleFactor3 = 0.03f; // 0.03 : downSample scale for step3
175     float scale = baseBlurScale;
176     if (blurRadius_ > radiusStep3) {
177         scale = scaleFactor3;
178     } else if (blurRadius_ > radiusStep2) {
179         scale = scaleFactor2;
180     } else if (blurRadius_ > radiusStep1) {
181         scale = scaleFactor1;
182     }
183     blurScale_ = scale;
184 }
185 
GetDescription() const186 std::string KawaseBlurFilter::GetDescription() const
187 {
188     return "blur radius is " + std::to_string(blurRadius_);
189 }
190 #endif
191 } // namespace Rosen
192 } // namespace OHOS