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