• 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 #include "effect/runtime_shader_builder.h"
21 
22 #ifdef USE_M133_SKIA
23 #include "include/core/SkM44.h"
24 #include "include/gpu/ganesh/GrDirectContext.h"
25 #else
26 #include "include/gpu/GrDirectContext.h"
27 #endif
28 
29 namespace OHOS {
30 namespace Rosen {
31 // Advanced Filter
32 #define PROPERTY_HIGPU_VERSION "const.gpu.vendor"
33 #define PROPERTY_DEBUG_SUPPORT_AF "persist.sys.graphic.supports_af"
34 static constexpr uint32_t BLUR_SAMPLE_COUNT = 5;
35 
36 // Advanced Filter: we can get normalized uv offset from width and height
37 struct OffsetInfo {
38     float offsetX;
39     float offsetY;
40     int width;
41     int height;
42 };
43 
44 // Advanced Filter
IsAdvancedFilterUsable()45 static bool IsAdvancedFilterUsable()
46 {
47     return false;
48 }
49 
50 static const bool IS_ADVANCED_FILTER_USABLE_CHECK_ONCE = IsAdvancedFilterUsable();
51 
KawaseBlurFilter()52 KawaseBlurFilter::KawaseBlurFilter()
53 {
54     std::string blurString(
55         R"(
56         uniform shader imageInput;
57         uniform float2 in_blurOffset;
58         uniform float2 in_maxSizeXY;
59 
60         half4 main(float2 xy) {
61             half4 c = imageInput.eval(xy);
62             c += imageInput.eval(float2(clamp(in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
63                                         clamp(in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
64             c += imageInput.eval(float2(clamp(in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
65                                         clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
66             c += imageInput.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
67                                         clamp(in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
68             c += imageInput.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
69                                         clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
70             return half4(c.rgb * 0.2, 1.0);
71         }
72     )");
73 
74     std::string mixString(
75         R"(
76         uniform shader blurredInput;
77         uniform shader originalInput;
78         uniform float mixFactor;
79         uniform float inColorFactor;
80 
81         highp float random(float2 xy) {
82             float t = dot(xy, float2(78.233, 12.9898));
83             return fract(sin(t) * 43758.5453);
84         }
85         half4 main(float2 xy) {
86             highp float noiseGranularity = inColorFactor / 255.0;
87             half4 finalColor = mix(originalInput.eval(xy), blurredInput.eval(xy), mixFactor);
88             float noise  = mix(-noiseGranularity, noiseGranularity, random(xy));
89             finalColor.rgb += noise;
90             return finalColor;
91         }
92     )");
93 
94     auto blurEffect = Drawing::RuntimeEffect::CreateForShader(blurString);
95     if (!blurEffect) {
96         ROSEN_LOGE("KawaseBlurFilter::RuntimeShader blurEffect create failed");
97         return;
98     }
99     blurEffect_ = std::move(blurEffect);
100 
101     // Advanced Filter
102     if (IS_ADVANCED_FILTER_USABLE_CHECK_ONCE) {
103         setupBlurEffectAdvancedFilter();
104     }
105 
106     auto mixEffect = Drawing::RuntimeEffect::CreateForShader(mixString);
107     if (!mixEffect) {
108         ROSEN_LOGE("KawaseBlurFilter::RuntimeShader mixEffect create failed");
109         return;
110     }
111     mixEffect_ = std::move(mixEffect);
112 
113     SetupSimpleFilter();
114 }
115 
116 KawaseBlurFilter::~KawaseBlurFilter() = default;
117 
118 // Advanced Filter
setupBlurEffectAdvancedFilter()119 void KawaseBlurFilter::setupBlurEffectAdvancedFilter()
120 {
121     std::string blurStringAF(
122         R"(
123         uniform shader imageInput;
124         uniform float2 in_blurOffset[5];
125 
126         half4 main(float2 xy) {
127             half4 c = half4(0, 0, 0, 0);
128             for (int i = 0; i < 5; ++i) {
129                 c += imageInput.eval(float2(xy.x + in_blurOffset[i].x, xy.y + in_blurOffset[i].y));
130             }
131             return half4(c.rgb * 0.2, 1.0);
132         }
133     )");
134 
135     Drawing::RuntimeEffectOptions ops;
136     ops.useAF = true;
137     auto blurEffectAF = Drawing::RuntimeEffect::CreateForShader(blurStringAF, ops);
138     if (!blurEffectAF) {
139         ROSEN_LOGE("%s: RuntimeShader blurEffectAF create failed", __func__);
140         return;
141     }
142     blurEffectAF_ = std::move(blurEffectAF);
143 }
144 
SetupSimpleFilter()145 void KawaseBlurFilter::SetupSimpleFilter()
146 {
147     std::string simpleShader(
148         R"(
149         uniform shader imageInput;
150         half4 main(float2 xy) {
151             return imageInput.eval(xy);
152         }
153     )");
154 
155     auto simpleFilter = Drawing::RuntimeEffect::CreateForShader(simpleShader);
156     if (!simpleFilter) {
157         ROSEN_LOGE("KawaseBlurFilter::RuntimeShader Failed to create simple filter");
158         return;
159     }
160     simpleFilter_ = std::move(simpleFilter);
161 }
162 
getNormalizedOffset(SkV2 * offsets,const uint32_t offsetCount,const OffsetInfo & offsetInfo)163 static void getNormalizedOffset(SkV2* offsets, const uint32_t offsetCount, const OffsetInfo& offsetInfo)
164 {
165     if (offsets == nullptr || offsetCount != BLUR_SAMPLE_COUNT) {
166         ROSEN_LOGE("%s: Invalid offsets.", __func__);
167         return;
168     }
169     if (std::fabs(offsetInfo.width) < 1e-6 || std::fabs(offsetInfo.height) < 1e-6) {
170         ROSEN_LOGE("%s: Invalid width or height.", __func__);
171         return;
172     }
173     SkV2 normalizedOffsets[BLUR_SAMPLE_COUNT] = {
174         SkV2{0.0f, 0.0f},
175         SkV2{offsetInfo.offsetX / offsetInfo.width, offsetInfo.offsetY / offsetInfo.height},
176         SkV2{-offsetInfo.offsetX / offsetInfo.width, offsetInfo.offsetY / offsetInfo.height},
177         SkV2{offsetInfo.offsetX / offsetInfo.width, -offsetInfo.offsetY / offsetInfo.height},
178         SkV2{-offsetInfo.offsetX / offsetInfo.width, -offsetInfo.offsetY / offsetInfo.height}
179     };
180     for (uint32_t i = 0; i < BLUR_SAMPLE_COUNT; ++i) {
181         offsets[i] = normalizedOffsets[i];
182     }
183 }
184 
GetShaderTransform(const Drawing::Canvas * canvas,const Drawing::Rect & blurRect,float scaleW,float scaleH)185 Drawing::Matrix KawaseBlurFilter::GetShaderTransform(const Drawing::Canvas* canvas, const Drawing::Rect& blurRect,
186     float scaleW, float scaleH)
187 {
188     Drawing::Matrix matrix;
189     matrix.SetScale(scaleW, scaleH);
190     Drawing::Matrix translateMatrix;
191     translateMatrix.Translate(blurRect.GetLeft(), blurRect.GetTop());
192     matrix.PostConcat(translateMatrix);
193     return matrix;
194 }
195 
CheckInputImage(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const KawaseParameter & param,std::shared_ptr<Drawing::Image> & checkedImage)196 void KawaseBlurFilter::CheckInputImage(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
197     const KawaseParameter& param, std::shared_ptr<Drawing::Image>& checkedImage)
198 {
199 #ifdef RS_ENABLE_GPU
200     auto src = param.src;
201     auto srcRect = Drawing::RectI(src.GetLeft(), src.GetTop(), src.GetRight(), src.GetBottom());
202     if (image->GetImageInfo().GetBound() != srcRect) {
203         auto resizedImage = std::make_shared<Drawing::Image>();
204         auto gpuCtx = canvas.GetGPUContext();
205         if ((gpuCtx == nullptr) || (resizedImage == nullptr)) {
206             ROSEN_LOGE("KawaseBlurFilter::canvas context or resizedImage is null.");
207             return;
208         }
209 
210         if (resizedImage->BuildSubset(image, srcRect, *gpuCtx)) {
211             checkedImage = resizedImage;
212             ROSEN_LOGD("KawaseBlurFilter::resize image success");
213         } else {
214             ROSEN_LOGE("KawaseBlurFilter::resize image failed, use original image");
215         }
216     }
217 #endif
218 }
219 
OutputOriginalImage(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const KawaseParameter & param)220 void KawaseBlurFilter::OutputOriginalImage(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
221     const KawaseParameter& param)
222 {
223     auto src = param.src;
224     auto dst = param.dst;
225     Drawing::Brush brush;
226     if (param.colorFilter) {
227         Drawing::Filter filter;
228         filter.SetColorFilter(param.colorFilter);
229         brush.SetFilter(filter);
230     }
231     Drawing::Matrix inputMatrix;
232     float scaleW = dst.GetWidth() / image->GetWidth();
233     float scaleH = dst.GetHeight() / image->GetHeight();
234     inputMatrix.Translate(-src.GetLeft(), -src.GetTop());
235     inputMatrix.PostScale(scaleW, scaleH);
236     Drawing::Matrix matrix;
237     matrix.Translate(dst.GetLeft(), dst.GetTop());
238     inputMatrix.PostConcat(matrix);
239     Drawing::SamplingOptions linear(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
240     const auto inputShader = Drawing::ShaderEffect::CreateImageShader(*image, Drawing::TileMode::CLAMP,
241         Drawing::TileMode::CLAMP, linear, inputMatrix);
242     brush.SetShaderEffect(inputShader);
243     canvas.AttachBrush(brush);
244     canvas.DrawRect(dst);
245     canvas.DetachBrush();
246 }
247 
ApplySimpleFilter(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & input,const Drawing::Matrix & blurMatrix,const Drawing::ImageInfo & scaledInfo,const Drawing::SamplingOptions & linear) const248 std::shared_ptr<Drawing::ShaderEffect> KawaseBlurFilter::ApplySimpleFilter(Drawing::Canvas& canvas,
249     const std::shared_ptr<Drawing::Image>& input, const Drawing::Matrix& blurMatrix,
250     const Drawing::ImageInfo& scaledInfo, const Drawing::SamplingOptions& linear) const
251 {
252     Drawing::RuntimeShaderBuilder simpleBlurBuilder(simpleFilter_);
253     simpleBlurBuilder.SetChild("imageInput", Drawing::ShaderEffect::CreateImageShader(*input, Drawing::TileMode::CLAMP,
254         Drawing::TileMode::CLAMP, linear, blurMatrix));
255 #ifdef RS_ENABLE_GPU
256     std::shared_ptr<Drawing::Image> tmpSimpleBlur(simpleBlurBuilder.MakeImage(
257         canvas.GetGPUContext().get(), nullptr, scaledInfo, false));
258 #else
259     std::shared_ptr<Drawing::Image> tmpSimpleBlur(simpleBlurBuilder.MakeImage(nullptr, nullptr, scaledInfo, false));
260 #endif
261     if (tmpSimpleBlur == nullptr) {
262         return nullptr;
263     }
264     return Drawing::ShaderEffect::CreateImageShader(*tmpSimpleBlur, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP,
265         linear, Drawing::Matrix());
266 }
267 
ApplyKawaseBlur(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const KawaseParameter & param)268 bool KawaseBlurFilter::ApplyKawaseBlur(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
269     const KawaseParameter& param)
270 {
271     if (!blurEffect_ || !mixEffect_ || !image) {
272         ROSEN_LOGE("KawaseBlurFilter::shader error, use Gauss instead");
273         return false;
274     }
275     static auto useKawaseOriginal = RSSystemProperties::GetKawaseOriginalEnabled();
276     if (param.radius <= 0 || useKawaseOriginal) {
277         ROSEN_LOGD("KawaseBlurFilter::input invalid radius : %{public}d", param.radius);
278         OutputOriginalImage(canvas, image, param);
279         return true;
280     }
281     auto input = image;
282     CheckInputImage(canvas, image, param, input);
283     ComputeRadiusAndScale(param.radius);
284     RS_OPTIONAL_TRACE_BEGIN("ApplyKawaseBlur " + GetDescription());
285     int maxPasses = supportLargeRadius ? kMaxPassesLargeRadius : kMaxPasses;
286     float dilatedConvolutionFactor = supportLargeRadius ? kDilatedConvolutionLargeRadius : kDilatedConvolution;
287     if (abs(dilatedConvolutionFactor) <= 1e-6) {
288         dilatedConvolutionFactor = 4.6f; // 4.6 : radio between gauss and kawase
289     }
290     float tmpRadius = static_cast<float>(blurRadius_) / dilatedConvolutionFactor;
291     int numberOfPasses = std::min(maxPasses, std::max(static_cast<int>(ceil(tmpRadius)), 1)); // 1 : min pass num
292     float radiusByPasses = tmpRadius / numberOfPasses;
293     ROSEN_LOGD("KawaseBlurFilter::kawase radius : %{public}f, scale : %{public}f, pass num : %{public}d",
294         blurRadius_, blurScale_, numberOfPasses);
295     int width = std::max(static_cast<int>(std::ceil(param.dst.GetWidth())), input->GetWidth());
296     int height = std::max(static_cast<int>(std::ceil(param.dst.GetHeight())), input->GetHeight());
297     auto blurParams = BlurParams{numberOfPasses, width, height, radiusByPasses};
298     auto blurImage = ExecutePingPongBlur(canvas, input, param, blurParams);
299     RS_OPTIONAL_TRACE_END();
300     if (!blurImage) {
301         return false;
302     }
303     return ApplyBlur(canvas, input, blurImage, param);
304 }
305 
ExecutePingPongBlur(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & input,const KawaseParameter & inParam,const BlurParams & blur) const306 std::shared_ptr<Drawing::Image> KawaseBlurFilter::ExecutePingPongBlur(Drawing::Canvas& canvas,
307     const std::shared_ptr<Drawing::Image>& input, const KawaseParameter& inParam, const BlurParams& blur) const
308 {
309     auto originImageInfo = input->GetImageInfo();
310     auto scaledInfo = Drawing::ImageInfo(std::ceil(blur.width * blurScale_), std::ceil(blur.height * blurScale_),
311         originImageInfo.GetColorType(), originImageInfo.GetAlphaType(), originImageInfo.GetColorSpace());
312     Drawing::Matrix blurMatrix;
313     blurMatrix.Translate(-inParam.src.GetLeft(), -inParam.src.GetTop());
314     float scaleW = static_cast<float>(scaledInfo.GetWidth()) / input->GetWidth();
315     float scaleH = static_cast<float>(scaledInfo.GetHeight()) / input->GetHeight();
316     blurMatrix.PostScale(scaleW, scaleH);
317     Drawing::SamplingOptions linear(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
318 
319     // Advanced Filter: check is AF usable only the first time
320     bool isUsingAF = IS_ADVANCED_FILTER_USABLE_CHECK_ONCE && blurEffectAF_ != nullptr;
321     Drawing::RuntimeShaderBuilder blurBuilder(isUsingAF ? blurEffectAF_ : blurEffect_);
322     if (RSSystemProperties::GetBlurExtraFilterEnabled() && simpleFilter_) {
323         blurBuilder.SetChild("imageInput", ApplySimpleFilter(canvas, input, blurMatrix, scaledInfo, linear));
324     } else {
325         blurBuilder.SetChild("imageInput", Drawing::ShaderEffect::CreateImageShader(*input, Drawing::TileMode::CLAMP,
326             Drawing::TileMode::CLAMP, linear, blurMatrix));
327     }
328 
329     if (isUsingAF) {
330         SkV2 firstPassOffsets[BLUR_SAMPLE_COUNT];
331         OffsetInfo firstPassOffsetInfo = {blur.radiusByPass * blurScale_, blur.radiusByPass * blurScale_,
332             scaledInfo.GetWidth(), scaledInfo.GetHeight()};
333         getNormalizedOffset(firstPassOffsets, BLUR_SAMPLE_COUNT, firstPassOffsetInfo);
334         blurBuilder.SetUniform("in_blurOffset", firstPassOffsetInfo.offsetX, firstPassOffsetInfo.offsetY,
335             firstPassOffsetInfo.width, firstPassOffsetInfo.height);
336     } else {
337         blurBuilder.SetUniform("in_blurOffset", blur.radiusByPass * blurScale_, blur.radiusByPass * blurScale_);
338         blurBuilder.SetUniform("in_maxSizeXY", blur.width * blurScale_, blur.height * blurScale_);
339     }
340 #ifdef RS_ENABLE_GPU
341     std::shared_ptr<Drawing::Image> tmpBlur(blurBuilder.MakeImage(
342         canvas.GetGPUContext().get(), nullptr, scaledInfo, false));
343 #else
344     std::shared_ptr<Drawing::Image> tmpBlur(blurBuilder.MakeImage(nullptr, nullptr, scaledInfo, false));
345 #endif
346     // And now we'll build our chain of scaled blur stages
347     for (auto i = 1; i < blur.numberOfPasses; i++) {
348         const float stepScale = static_cast<float>(i) * blurScale_;
349         if (tmpBlur == nullptr) {
350             ROSEN_LOGE("KawaseBlurFilter::ExecutePingPongBlur tmpBlur is nullptr.");
351             return nullptr;
352         }
353         blurBuilder.SetChild("imageInput", Drawing::ShaderEffect::CreateImageShader(*tmpBlur, Drawing::TileMode::CLAMP,
354             Drawing::TileMode::CLAMP, linear, Drawing::Matrix()));
355 
356         // Advanced Filter
357         if (isUsingAF) {
358             SkV2 offsets[BLUR_SAMPLE_COUNT];
359             OffsetInfo offsetInfo = {blur.radiusByPass * stepScale, blur.radiusByPass * stepScale,
360                 scaledInfo.GetWidth(), scaledInfo.GetHeight()};
361             getNormalizedOffset(offsets, BLUR_SAMPLE_COUNT, offsetInfo);
362             blurBuilder.SetUniform("in_blurOffset", offsetInfo.offsetX, offsetInfo.offsetY, offsetInfo.width,
363                 offsetInfo.height);
364         } else {
365             blurBuilder.SetUniform("in_blurOffset", blur.radiusByPass * stepScale, blur.radiusByPass * stepScale);
366             blurBuilder.SetUniform("in_maxSizeXY", blur.width * blurScale_, blur.height * blurScale_);
367         }
368 #ifdef RS_ENABLE_GPU
369         tmpBlur = blurBuilder.MakeImage(canvas.GetGPUContext().get(), nullptr, scaledInfo, false);
370 #else
371         tmpBlur = blurBuilder.MakeImage(nullptr, nullptr, scaledInfo, false);
372 #endif
373     }
374     return tmpBlur;
375 }
376 
ApplyBlur(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const std::shared_ptr<Drawing::Image> & blurImage,const KawaseParameter & param) const377 bool KawaseBlurFilter::ApplyBlur(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
378     const std::shared_ptr<Drawing::Image>& blurImage, const KawaseParameter& param) const
379 {
380     if (!mixEffect_ || !image || !blurImage) {
381         ROSEN_LOGE("KawaseBlurFilter::ApplyBlur input error, use Gauss instead");
382         return false;
383     }
384     auto src = param.src;
385     auto dst = param.dst;
386     Drawing::SamplingOptions linear(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
387     const auto blurMatrix = GetShaderTransform(&canvas, dst, dst.GetWidth() / blurImage->GetWidth(),
388         dst.GetHeight() / blurImage->GetHeight());
389     const auto blurShader = Drawing::ShaderEffect::CreateImageShader(*blurImage, Drawing::TileMode::CLAMP,
390         Drawing::TileMode::CLAMP, linear, blurMatrix);
391     Drawing::Brush brush;
392     brush.SetAlphaF(param.alpha);
393     if (param.colorFilter) {
394         Drawing::Filter filter;
395         filter.SetColorFilter(param.colorFilter);
396         brush.SetFilter(filter);
397     }
398     static auto addRandomColor = RSSystemProperties::GetRandomColorEnabled();
399     if (addRandomColor) {
400         Drawing::Matrix inputMatrix;
401         inputMatrix.Translate(-src.GetLeft(), -src.GetTop());
402         inputMatrix.PostScale(dst.GetWidth() / image->GetWidth(), dst.GetHeight() / image->GetHeight());
403         Drawing::Matrix matrix;
404         matrix.Translate(dst.GetLeft(), dst.GetTop());
405         inputMatrix.PostConcat(matrix);
406         Drawing::RuntimeShaderBuilder mixBuilder(mixEffect_);
407         mixBuilder.SetChild("blurredInput", blurShader);
408         mixBuilder.SetChild("originalInput", Drawing::ShaderEffect::CreateImageShader(*image, Drawing::TileMode::CLAMP,
409             Drawing::TileMode::CLAMP, linear, inputMatrix));
410         float mixFactor = (abs(kMaxCrossFadeRadius) <= 1e-6) ? 1.f : (blurRadius_ / kMaxCrossFadeRadius);
411         mixBuilder.SetUniform("mixFactor", std::min(1.0f, mixFactor));
412         static auto factor = RSSystemProperties::GetKawaseRandomColorFactor();
413         mixBuilder.SetUniform("inColorFactor", factor);
414         ROSEN_LOGD("KawaseBlurFilter::kawase random color factor : %{public}f", factor);
415         brush.SetShaderEffect(mixBuilder.MakeShader(nullptr, image->IsOpaque()));
416     } else {
417         brush.SetShaderEffect(blurShader);
418     }
419     canvas.AttachBrush(brush);
420     canvas.DrawRect(dst);
421     canvas.DetachBrush();
422     return true;
423 }
424 
ComputeRadiusAndScale(int radius)425 void KawaseBlurFilter::ComputeRadiusAndScale(int radius)
426 {
427     blurRadius_ = radius * 4; // 4 : scale between gauss radius and kawase
428     AdjustRadiusAndScale();
429 }
430 
AdjustRadiusAndScale()431 void KawaseBlurFilter::AdjustRadiusAndScale()
432 {
433     static constexpr int radiusStep1 = 50; // 50 : radius step1
434     static constexpr int radiusStep2 = 150; // 150 : radius step2
435     static constexpr int radiusStep3 = 400; // 400 : radius step3
436     static constexpr float scaleFactor1 = 0.25f; // 0.25 : downSample scale for step1
437     static constexpr float scaleFactor2 = 0.125f; // 0.125 : downSample scale for step2
438     static constexpr float scaleFactor3 = 0.0625f; // 0.0625 : downSample scale for step3
439     auto radius = static_cast<int>(blurRadius_);
440     if (radius > radiusStep3) {
441         blurScale_ = scaleFactor3;
442     } else if (radius > radiusStep2) {
443         blurScale_ = scaleFactor2;
444     } else if (radius > radiusStep1) {
445         blurScale_ = scaleFactor1;
446     } else {
447         blurScale_ = baseBlurScale;
448     }
449 }
450 
GetDescription() const451 std::string KawaseBlurFilter::GetDescription() const
452 {
453     return "blur radius is " + std::to_string(blurRadius_);
454 }
455 } // namespace Rosen
456 } // namespace OHOS