@@ -96,13 +96,17 @@ void KawaseBlurDualFilter::blurInto(const sk_sp<SkSurface>& drawSurface,
9696void KawaseBlurDualFilter::blurInto (const sk_sp<SkSurface>& drawSurface, sk_sp<SkShader> input,
9797 const float inverseScale, const float radius,
9898 const float alpha) const {
99- SkRuntimeShaderBuilder blurBuilder (mBlurEffect );
100- blurBuilder.child (" child" ) = std::move (input);
101- blurBuilder.uniform (" in_inverseScale" ) = inverseScale;
102- blurBuilder.uniform (" in_blurOffset" ) = radius;
103- blurBuilder.uniform (" in_crossFade" ) = alpha;
10499 SkPaint paint;
105- paint.setShader (blurBuilder.makeShader (nullptr ));
100+ if (radius == 0 ) {
101+ paint.setShader (std::move (input));
102+ paint.setAlphaf (alpha);
103+ } else {
104+ SkRuntimeShaderBuilder blurBuilder (mBlurEffect );
105+ blurBuilder.child (" child" ) = std::move (input);
106+ blurBuilder.uniform (" in_blurOffset" ) = radius;
107+ blurBuilder.uniform (" in_crossFade" ) = alpha;
108+ paint.setShader (blurBuilder.makeShader (nullptr ));
109+ }
106110 paint.setBlendMode (alpha == 1 .0f ? SkBlendMode::kSrc : SkBlendMode::kSrcOver );
107111 drawSurface->getCanvas ()->drawPaint (paint);
108112}
@@ -116,32 +120,35 @@ sk_sp<SkImage> KawaseBlurDualFilter::generate(SkiaGpuContext* context, const uin
116120
117121 // Use a variable number of blur passes depending on the radius. The non-integer part of this
118122 // calculation is used to mix the final pass into the second-last with an alpha blend.
119- constexpr int kMaxSurfaces = 4 ;
120- const float filterDepth =
121- std::min (kMaxSurfaces - 1 .0f , 1 .0f + std::max (0 .0f , log2f (radius * kInputScale )));
123+ constexpr int kMaxSurfaces = 3 ;
124+ const float filterDepth = std::min (kMaxSurfaces - 1 .0f , radius * kInputScale / 2 .5f );
122125 const int filterPasses = std::min (kMaxSurfaces - 1 , static_cast <int >(ceil (filterDepth)));
123126
124- // Render into surfaces downscaled by 1x, 1x, 2x, and 4x from the initial downscale.
127+ // Render into surfaces downscaled by 1x, 2x, and 4x from the initial downscale.
125128 sk_sp<SkSurface> surfaces[kMaxSurfaces ] =
126129 {filterPasses >= 0 ? makeSurface (context, blurRect, 1 * kInverseInputScale ) : nullptr ,
127- filterPasses >= 1 ? makeSurface (context, blurRect, 1 * kInverseInputScale ) : nullptr ,
128- filterPasses >= 2 ? makeSurface (context, blurRect, 2 * kInverseInputScale ) : nullptr ,
129- filterPasses >= 3 ? makeSurface (context, blurRect, 4 * kInverseInputScale ) : nullptr };
130-
131- // These weights for scaling offsets per-pass are handpicked to look good at 1 <= radius <= 600.
132- static const float kWeights [7 ] = {1 .0f , 2 .0f , 3 .5f , 1 .0f , 2 .0f , 2 .0f , 2 .0f };
130+ filterPasses >= 1 ? makeSurface (context, blurRect, 2 * kInverseInputScale ) : nullptr ,
131+ filterPasses >= 2 ? makeSurface (context, blurRect, 4 * kInverseInputScale ) : nullptr };
132+
133+ // These weights for scaling offsets per-pass are handpicked to look good at 1 <= radius <= 250.
134+ static const float kWeights [5 ] = {
135+ 1 .0f , // 1st downsampling pass
136+ 1 .0f , // 2nd downsampling pass
137+ 1 .0f , // 3rd downsampling pass
138+ 0 .0f , // 1st upscaling pass. Set to zero to upscale without blurring for performance.
139+ 1 .0f , // 2nd upscaling pass
140+ };
133141
134142 // Kawase is an approximation of Gaussian, but behaves differently because it is made up of many
135143 // simpler blurs. A transformation is required to approximate the same effect as Gaussian.
136- float sumSquaredR = powf (kWeights [0 ] * powf ( 2 . 0f , 1 ) , 2 .0f );
144+ float sumSquaredR = powf (kWeights [0 ], 2 .0f );
137145 for (int i = 0 ; i < filterPasses; i++) {
138146 const float alpha = std::min (1 .0f , filterDepth - i);
139- sumSquaredR += powf (powf (2 .0f , i + 1 ) * alpha * kWeights [1 + i], 2 .0f );
140- sumSquaredR += powf (powf (2 .0f , i + 1 ) * alpha * kWeights [6 - i], 2 .0f );
147+ sumSquaredR += powf (powf (2 .0f , i) * alpha * kWeights [1 + i] / kInputScale , 2 .0f );
148+ sumSquaredR += powf (powf (2 .0f , i + 1 ) * alpha * kWeights [4 - i] / kInputScale , 2 .0f );
141149 }
142- // Solve for R = sqrt(sum(r_i^2)). Divide R by hypot(1,1) to find some (x,y) offsets.
143- const float step = M_SQRT1_2 *
144- sqrtf (max (0 .0f , (powf (radius, 2 .0f ) - powf (kInverseInputScale , 2 .0f )) / sumSquaredR));
150+ // Solve for R = sqrt(sum(r_i^2)).
151+ const float step = radius * sqrt (1 .0f / sumSquaredR);
145152
146153 // Start by downscaling and doing the first blur pass.
147154 {
@@ -162,7 +169,7 @@ sk_sp<SkImage> KawaseBlurDualFilter::generate(SkiaGpuContext* context, const uin
162169 }
163170 // Finally blur+upscale back to our original size.
164171 for (int i = filterPasses - 1 ; i >= 0 ; i--) {
165- blurInto (surfaces[i], surfaces[i + 1 ]->makeImageSnapshot (), kWeights [6 - i] * step,
172+ blurInto (surfaces[i], surfaces[i + 1 ]->makeImageSnapshot (), kWeights [4 - i] * step,
166173 std::min (1 .0f , filterDepth - i));
167174 }
168175 return surfaces[0 ]->makeImageSnapshot ();
0 commit comments