While working on my new project I (a bit accidentally to be honest 🙂 ) came up with a gaussian blur implementation which creates a smooth looking blurred images while requiring much less render passes than the Starling's BlurFilter. For higher blur values it's even 10x more efficient.
Here's an animated example with blur strength changing from 0 to 30:
On my MacBook Air from 2011 and on Galaxy S4 I'm getting constant 60 FPS for all blur values.
How does it work?
I started with Daniel's BlurFilter and then went on changing the bottlenecks. I used precalculated weights instead of computing them before each render pass. Then I triend to experiment with the maximum blur strength I can get from one pass without losing the quality. It turned out I could use strength value of about 1.25 per pass and still have effects not worse than with original implementation (which used strength value of 1 per pass). The biggest performance improvement was "skipping" unnecessary passes when blurring an image with strength higher than 1.25. I introduced a new parameter - a ratio of strength incrementation per each pass after the first one, when strenghth value is over 1.25. The default value for this ratio is 2.5, so the first pass is done with strength 1.25, second with 2.5*1.25=3.125, etc.
For strength of 5 ratios used for each horizontal and vertical passes are: 3.125, 1.25, 0.625 (total of 6 passes, compared to 10 with BlurFilter) and for strength of 50: 19.53125, 18.28125, 7.8125, 3.125, 1.25 (total of 10, 100 with BlurFilter). I also apply the higher strength passes first and lower strength last, to smooth everything out in the final pass.
Here's how each render pass looks like with this approach (strength 50) - horizontal passes in the top row, vertical in the bottom one (image is quite big, you should probably open in in a new tab):
As you can see first passes use very high offset values and create an image repeated couple of times over the original (which is exactly what the gaussian blur does, but with much smaller offsets) and the last ones simply smooth everything out (the offset values used are between 0.0 - 1.25).
I also compared the results of this blur with PhotoShop's gaussian blur. Here's an image showing which pixels were rendered differently in PS (both images were merged with Difference blend mode and then inverted):
As you can see there's only a very little difference. You can find this implementation (as a Starling extension) on GitHub, along with a demo project:
I used EasyAGAL for the shaders, so you'll need this one as well:
I didn't use Starling's FragmentFilter class for this, so everything is done using my TextureProcessor implementation, but doing a FragmentFilter based on my code should be fairly fast and simple.