Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 4b77e77

Browse files
[Impeller] improve blur performance for Android and iPad Pro. (#39291)
* [Impeller] improve gaussian blur performance on Android * ++ * ++
1 parent 29d0984 commit 4b77e77

File tree

10 files changed

+160
-85
lines changed

10 files changed

+160
-85
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,7 +1337,9 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/border_mask_blur.vert + ../../.
13371337
ORIGIN: ../../../flutter/impeller/entity/shaders/color_matrix_color_filter.frag + ../../../flutter/LICENSE
13381338
ORIGIN: ../../../flutter/impeller/entity/shaders/color_matrix_color_filter.vert + ../../../flutter/LICENSE
13391339
ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur.frag + ../../../flutter/LICENSE
1340+
ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur.glsl + ../../../flutter/LICENSE
13401341
ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur.vert + ../../../flutter/LICENSE
1342+
ORIGIN: ../../../flutter/impeller/entity/shaders/gaussian_blur_decal.frag + ../../../flutter/LICENSE
13411343
ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag + ../../../flutter/LICENSE
13421344
ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert + ../../../flutter/LICENSE
13431345
ORIGIN: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.frag + ../../../flutter/LICENSE
@@ -3813,7 +3815,9 @@ FILE: ../../../flutter/impeller/entity/shaders/border_mask_blur.vert
38133815
FILE: ../../../flutter/impeller/entity/shaders/color_matrix_color_filter.frag
38143816
FILE: ../../../flutter/impeller/entity/shaders/color_matrix_color_filter.vert
38153817
FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.frag
3818+
FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.glsl
38163819
FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.vert
3820+
FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur_decal.frag
38173821
FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag
38183822
FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert
38193823
FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas_sdf.frag

impeller/compiler/shader_lib/impeller/texture.glsl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ vec4 IPSample(sampler2D texture_sampler, vec2 coords, float y_coord_scale) {
1919
return texture(texture_sampler, coords);
2020
}
2121

22+
vec2 IPRemapCoords(vec2 coords, float y_coord_scale) {
23+
if (y_coord_scale < 0.0) {
24+
coords.y = 1.0 - coords.y;
25+
}
26+
return coords;
27+
}
28+
2229
/// Sample from a texture.
2330
///
2431
/// If `y_coord_scale` < 0.0, the Y coordinate is flipped. This is useful
@@ -119,6 +126,15 @@ vec4 IPSampleLinearWithTileMode(sampler2D tex,
119126
y_coord_scale, half_texel);
120127
}
121128

129+
/// Sample a texture with decal tile mode.
130+
vec4 IPSampleDecal(sampler2D texture_sampler, vec2 coords) {
131+
if (any(lessThan(coords, vec2(0))) ||
132+
any(greaterThanEqual(coords, vec2(1)))) {
133+
return vec4(0);
134+
}
135+
return texture(texture_sampler, coords);
136+
}
137+
122138
/// Sample a texture, emulating a specific tile mode.
123139
///
124140
/// This is useful for Impeller graphics backend that don't have native support

impeller/entity/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ impeller_shaders("entity_shaders") {
3131
"shaders/color_matrix_color_filter.frag",
3232
"shaders/color_matrix_color_filter.vert",
3333
"shaders/gaussian_blur.frag",
34+
"shaders/gaussian_blur_decal.frag",
3435
"shaders/gaussian_blur.vert",
3536
"shaders/glyph_atlas.frag",
3637
"shaders/glyph_atlas.vert",

impeller/entity/contents/content_context.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ ContentContext::ContentContext(std::shared_ptr<Context> context)
207207
CreateDefaultPipeline<TiledTexturePipeline>(*context_);
208208
gaussian_blur_pipelines_[{}] =
209209
CreateDefaultPipeline<GaussianBlurPipeline>(*context_);
210+
gaussian_blur_decal_pipelines_[{}] =
211+
CreateDefaultPipeline<GaussianBlurDecalPipeline>(*context_);
210212
border_mask_blur_pipelines_[{}] =
211213
CreateDefaultPipeline<BorderMaskBlurPipeline>(*context_);
212214
morphology_filter_pipelines_[{}] =

impeller/entity/contents/content_context.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "impeller/entity/entity.h"
3737
#include "impeller/entity/gaussian_blur.frag.h"
3838
#include "impeller/entity/gaussian_blur.vert.h"
39+
#include "impeller/entity/gaussian_blur_decal.frag.h"
3940
#include "impeller/entity/glyph_atlas.frag.h"
4041
#include "impeller/entity/glyph_atlas.vert.h"
4142
#include "impeller/entity/glyph_atlas_sdf.frag.h"
@@ -146,6 +147,8 @@ using TiledTexturePipeline = RenderPipelineT<TiledTextureFillVertexShader,
146147
TiledTextureFillFragmentShader>;
147148
using GaussianBlurPipeline =
148149
RenderPipelineT<GaussianBlurVertexShader, GaussianBlurFragmentShader>;
150+
using GaussianBlurDecalPipeline =
151+
RenderPipelineT<GaussianBlurVertexShader, GaussianBlurDecalFragmentShader>;
149152
using BorderMaskBlurPipeline =
150153
RenderPipelineT<BorderMaskBlurVertexShader, BorderMaskBlurFragmentShader>;
151154
using MorphologyFilterPipeline =
@@ -281,6 +284,11 @@ class ContentContext {
281284
return GetPipeline(gaussian_blur_pipelines_, opts);
282285
}
283286

287+
std::shared_ptr<Pipeline<PipelineDescriptor>> GetGaussianBlurDecalPipeline(
288+
ContentContextOptions opts) const {
289+
return GetPipeline(gaussian_blur_decal_pipelines_, opts);
290+
}
291+
284292
std::shared_ptr<Pipeline<PipelineDescriptor>> GetBorderMaskBlurPipeline(
285293
ContentContextOptions opts) const {
286294
return GetPipeline(border_mask_blur_pipelines_, opts);
@@ -455,6 +463,7 @@ class ContentContext {
455463
mutable Variants<TexturePipeline> texture_pipelines_;
456464
mutable Variants<TiledTexturePipeline> tiled_texture_pipelines_;
457465
mutable Variants<GaussianBlurPipeline> gaussian_blur_pipelines_;
466+
mutable Variants<GaussianBlurDecalPipeline> gaussian_blur_decal_pipelines_;
458467
mutable Variants<BorderMaskBlurPipeline> border_mask_blur_pipelines_;
459468
mutable Variants<MorphologyFilterPipeline> morphology_filter_pipelines_;
460469
mutable Variants<ColorMatrixColorFilterPipeline>

impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -183,13 +183,12 @@ std::optional<Snapshot> DirectionalGaussianBlurFilterContents::RenderFilter(
183183

184184
VS::FrameInfo frame_info;
185185
frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1));
186-
187-
FS::FragInfo frag_info;
188-
frag_info.texture_sampler_y_coord_scale =
186+
frame_info.texture_sampler_y_coord_scale =
189187
input_snapshot->texture->GetYCoordScale();
190-
frag_info.alpha_mask_sampler_y_coord_scale =
188+
frame_info.alpha_mask_sampler_y_coord_scale =
191189
source_snapshot->texture->GetYCoordScale();
192190

191+
FS::FragInfo frag_info;
193192
auto r = Radius{transformed_blur_radius_length};
194193
frag_info.blur_sigma = Sigma{r}.sigma;
195194
frag_info.blur_radius = r.radius;
@@ -198,7 +197,6 @@ std::optional<Snapshot> DirectionalGaussianBlurFilterContents::RenderFilter(
198197
frag_info.blur_direction =
199198
pass_transform.Invert().TransformDirection(Vector2(1, 0)).Normalize();
200199

201-
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
202200
frag_info.src_factor = src_color_factor_;
203201
frag_info.inner_blur_factor = inner_blur_factor_;
204202
frag_info.outer_blur_factor = outer_blur_factor_;
@@ -207,19 +205,48 @@ std::optional<Snapshot> DirectionalGaussianBlurFilterContents::RenderFilter(
207205
Command cmd;
208206
cmd.label = SPrintF("Gaussian Blur Filter (Radius=%.2f)",
209207
transformed_blur_radius_length);
208+
cmd.BindVertices(vtx_buffer);
209+
210210
auto options = OptionsFromPass(pass);
211211
options.blend_mode = BlendMode::kSource;
212-
cmd.pipeline = renderer.GetGaussianBlurPipeline(options);
213-
cmd.BindVertices(vtx_buffer);
212+
auto input_descriptor = input_snapshot->sampler_descriptor;
213+
auto source_descriptor = source_snapshot->sampler_descriptor;
214+
switch (tile_mode_) {
215+
case Entity::TileMode::kDecal:
216+
cmd.pipeline = renderer.GetGaussianBlurDecalPipeline(options);
217+
break;
218+
case Entity::TileMode::kClamp:
219+
cmd.pipeline = renderer.GetGaussianBlurPipeline(options);
220+
input_descriptor.width_address_mode = SamplerAddressMode::kClampToEdge;
221+
input_descriptor.height_address_mode = SamplerAddressMode::kClampToEdge;
222+
source_descriptor.width_address_mode = SamplerAddressMode::kClampToEdge;
223+
source_descriptor.height_address_mode =
224+
SamplerAddressMode::kClampToEdge;
225+
break;
226+
case Entity::TileMode::kMirror:
227+
cmd.pipeline = renderer.GetGaussianBlurPipeline(options);
228+
input_descriptor.width_address_mode = SamplerAddressMode::kMirror;
229+
input_descriptor.height_address_mode = SamplerAddressMode::kMirror;
230+
source_descriptor.width_address_mode = SamplerAddressMode::kMirror;
231+
source_descriptor.height_address_mode = SamplerAddressMode::kMirror;
232+
break;
233+
case Entity::TileMode::kRepeat:
234+
cmd.pipeline = renderer.GetGaussianBlurPipeline(options);
235+
input_descriptor.width_address_mode = SamplerAddressMode::kRepeat;
236+
input_descriptor.height_address_mode = SamplerAddressMode::kRepeat;
237+
source_descriptor.width_address_mode = SamplerAddressMode::kRepeat;
238+
source_descriptor.height_address_mode = SamplerAddressMode::kRepeat;
239+
break;
240+
}
214241

215242
FS::BindTextureSampler(
216243
cmd, input_snapshot->texture,
217244
renderer.GetContext()->GetSamplerLibrary()->GetSampler(
218-
input_snapshot->sampler_descriptor));
245+
input_descriptor));
219246
FS::BindAlphaMaskSampler(
220247
cmd, source_snapshot->texture,
221248
renderer.GetContext()->GetSamplerLibrary()->GetSampler(
222-
source_snapshot->sampler_descriptor));
249+
source_descriptor));
223250
VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info));
224251
FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info));
225252

@@ -281,7 +308,7 @@ std::optional<Rect> DirectionalGaussianBlurFilterContents::GetFilterCoverage(
281308

282309
auto transform = inputs[0]->GetTransform(entity) * effect_transform;
283310
auto transformed_blur_vector =
284-
transform.TransformDirection(blur_direction_ * Radius{blur_sigma_}.radius)
311+
transform.TransformDirection(blur_direction_* Radius{blur_sigma_}.radius)
285312
.Abs();
286313
auto extent = coverage->size + transformed_blur_vector * 2;
287314
return Rect(coverage->origin - transformed_blur_vector,

impeller/entity/shaders/gaussian_blur.frag

Lines changed: 3 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,80 +2,10 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
// 1D (directional) gaussian blur.
6-
//
7-
// Paths for future optimization:
8-
// * Remove the uv bounds multiplier in SampleColor by adding optional
9-
// support for SamplerAddressMode::ClampToBorder in the texture sampler.
10-
// * Render both blur passes into a smaller texture than the source image
11-
// (~1/radius size).
12-
// * If doing the small texture render optimization, cache misses can be
13-
// reduced in the first pass by sampling the source textures with a mip
14-
// level of log2(min_radius).
15-
16-
#include <impeller/constants.glsl>
17-
#include <impeller/gaussian.glsl>
185
#include <impeller/texture.glsl>
19-
#include <impeller/types.glsl>
20-
21-
uniform sampler2D texture_sampler;
22-
uniform sampler2D alpha_mask_sampler;
23-
24-
uniform FragInfo {
25-
float texture_sampler_y_coord_scale;
26-
float alpha_mask_sampler_y_coord_scale;
27-
28-
vec2 texture_size;
29-
vec2 blur_direction;
306

31-
float tile_mode;
32-
33-
// The blur sigma and radius have a linear relationship which is defined
34-
// host-side, but both are useful controls here. Sigma (pixels per standard
35-
// deviation) is used to define the gaussian function itself, whereas the
36-
// radius is used to limit how much of the function is integrated.
37-
float blur_sigma;
38-
float blur_radius;
39-
40-
float src_factor;
41-
float inner_blur_factor;
42-
float outer_blur_factor;
7+
vec4 Sample(sampler2D tex, vec2 coords) {
8+
return texture(tex, coords);
439
}
44-
frag_info;
45-
46-
in vec2 v_texture_coords;
47-
in vec2 v_src_texture_coords;
4810

49-
out vec4 frag_color;
50-
51-
void main() {
52-
vec4 total_color = vec4(0);
53-
float gaussian_integral = 0;
54-
vec2 blur_uv_offset = frag_info.blur_direction / frag_info.texture_size;
55-
56-
for (float i = -frag_info.blur_radius; i <= frag_info.blur_radius; i++) {
57-
float gaussian = IPGaussian(i, frag_info.blur_sigma);
58-
gaussian_integral += gaussian;
59-
total_color +=
60-
gaussian *
61-
IPSampleWithTileMode(
62-
texture_sampler, // sampler
63-
v_texture_coords + blur_uv_offset * i, // texture coordinates
64-
frag_info.texture_sampler_y_coord_scale, // y coordinate scale
65-
frag_info.tile_mode // tile mode
66-
);
67-
}
68-
69-
vec4 blur_color = total_color / gaussian_integral;
70-
71-
vec4 src_color = IPSampleWithTileMode(
72-
alpha_mask_sampler, // sampler
73-
v_src_texture_coords, // texture coordinates
74-
frag_info.alpha_mask_sampler_y_coord_scale, // y coordinate scale
75-
frag_info.tile_mode // tile mode
76-
);
77-
float blur_factor = frag_info.inner_blur_factor * float(src_color.a > 0) +
78-
frag_info.outer_blur_factor * float(src_color.a == 0);
79-
80-
frag_color = blur_color * blur_factor + src_color * frag_info.src_factor;
81-
}
11+
#include "gaussian_blur.glsl"
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// 1D (directional) gaussian blur.
6+
//
7+
// Paths for future optimization:
8+
// * Remove the uv bounds multiplier in SampleColor by adding optional
9+
// support for SamplerAddressMode::ClampToBorder in the texture sampler.
10+
// * Render both blur passes into a smaller texture than the source image
11+
// (~1/radius size).
12+
// * If doing the small texture render optimization, cache misses can be
13+
// reduced in the first pass by sampling the source textures with a mip
14+
// level of log2(min_radius).
15+
16+
#include <impeller/constants.glsl>
17+
#include <impeller/gaussian.glsl>
18+
#include <impeller/texture.glsl>
19+
#include <impeller/types.glsl>
20+
21+
uniform sampler2D texture_sampler;
22+
uniform sampler2D alpha_mask_sampler;
23+
24+
uniform FragInfo {
25+
vec2 texture_size;
26+
vec2 blur_direction;
27+
28+
// The blur sigma and radius have a linear relationship which is defined
29+
// host-side, but both are useful controls here. Sigma (pixels per standard
30+
// deviation) is used to define the gaussian function itself, whereas the
31+
// radius is used to limit how much of the function is integrated.
32+
float blur_sigma;
33+
float blur_radius;
34+
35+
float src_factor;
36+
float inner_blur_factor;
37+
float outer_blur_factor;
38+
}
39+
frag_info;
40+
41+
in vec2 v_texture_coords;
42+
in vec2 v_src_texture_coords;
43+
44+
out vec4 frag_color;
45+
46+
void main() {
47+
vec4 total_color = vec4(0);
48+
float gaussian_integral = 0;
49+
vec2 blur_uv_offset = frag_info.blur_direction / frag_info.texture_size;
50+
51+
for (float i = -frag_info.blur_radius; i <= frag_info.blur_radius; i++) {
52+
float gaussian = IPGaussian(i, frag_info.blur_sigma);
53+
gaussian_integral += gaussian;
54+
total_color +=
55+
gaussian *
56+
Sample(texture_sampler, // sampler
57+
v_texture_coords + blur_uv_offset * i // texture coordinates
58+
);
59+
}
60+
61+
vec4 blur_color = total_color / gaussian_integral;
62+
63+
vec4 src_color = Sample(alpha_mask_sampler, // sampler
64+
v_src_texture_coords // texture coordinates
65+
);
66+
float blur_factor = frag_info.inner_blur_factor * float(src_color.a > 0) +
67+
frag_info.outer_blur_factor * float(src_color.a == 0);
68+
69+
frag_color = blur_color * blur_factor + src_color * frag_info.src_factor;
70+
}

impeller/entity/shaders/gaussian_blur.vert

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
#include <impeller/texture.glsl>
56
#include <impeller/types.glsl>
67

78
uniform FrameInfo {
89
mat4 mvp;
10+
float texture_sampler_y_coord_scale;
11+
float alpha_mask_sampler_y_coord_scale;
912
}
1013
frame_info;
1114

@@ -18,6 +21,8 @@ out vec2 v_src_texture_coords;
1821

1922
void main() {
2023
gl_Position = frame_info.mvp * vec4(vertices, 0.0, 1.0);
21-
v_texture_coords = texture_coords;
22-
v_src_texture_coords = src_texture_coords;
24+
v_texture_coords =
25+
IPRemapCoords(texture_coords, frame_info.texture_sampler_y_coord_scale);
26+
v_src_texture_coords = IPRemapCoords(
27+
src_texture_coords, frame_info.alpha_mask_sampler_y_coord_scale);
2328
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include <impeller/texture.glsl>
6+
7+
vec4 Sample(sampler2D tex, vec2 coords) {
8+
return IPSampleDecal(tex, coords);
9+
}
10+
11+
#include "gaussian_blur.glsl"

0 commit comments

Comments
 (0)