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

Commit 248290d

Browse files
[Impeller] improve blur performance for Android and iPad Pro. (#39291) (#39367)
* [Impeller] improve gaussian blur performance on Android * ++ * ++ Co-authored-by: Jonah Williams <[email protected]>
1 parent e56e58f commit 248290d

File tree

10 files changed

+157
-84
lines changed

10 files changed

+157
-84
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,7 +1340,9 @@ FILE: ../../../flutter/impeller/entity/shaders/border_mask_blur.vert
13401340
FILE: ../../../flutter/impeller/entity/shaders/color_matrix_color_filter.frag
13411341
FILE: ../../../flutter/impeller/entity/shaders/color_matrix_color_filter.vert
13421342
FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.frag
1343+
FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.glsl
13431344
FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.vert
1345+
FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur_decal.frag
13441346
FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag
13451347
FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert
13461348
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
@@ -33,6 +33,7 @@ impeller_shaders("entity_shaders") {
3333
"shaders/color_matrix_color_filter.frag",
3434
"shaders/color_matrix_color_filter.vert",
3535
"shaders/gaussian_blur.frag",
36+
"shaders/gaussian_blur_decal.frag",
3637
"shaders/gaussian_blur.vert",
3738
"shaders/glyph_atlas.frag",
3839
"shaders/glyph_atlas.vert",

impeller/entity/contents/content_context.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ ContentContext::ContentContext(std::shared_ptr<Context> context)
205205
CreateDefaultPipeline<TiledTexturePipeline>(*context_);
206206
gaussian_blur_pipelines_[{}] =
207207
CreateDefaultPipeline<GaussianBlurPipeline>(*context_);
208+
gaussian_blur_decal_pipelines_[{}] =
209+
CreateDefaultPipeline<GaussianBlurDecalPipeline>(*context_);
208210
border_mask_blur_pipelines_[{}] =
209211
CreateDefaultPipeline<BorderMaskBlurPipeline>(*context_);
210212
morphology_filter_pipelines_[{}] =

impeller/entity/contents/content_context.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "impeller/entity/entity.h"
3939
#include "impeller/entity/gaussian_blur.frag.h"
4040
#include "impeller/entity/gaussian_blur.vert.h"
41+
#include "impeller/entity/gaussian_blur_decal.frag.h"
4142
#include "impeller/entity/glyph_atlas.frag.h"
4243
#include "impeller/entity/glyph_atlas.vert.h"
4344
#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);
@@ -460,6 +468,7 @@ class ContentContext {
460468
mutable Variants<TexturePipeline> texture_pipelines_;
461469
mutable Variants<TiledTexturePipeline> tiled_texture_pipelines_;
462470
mutable Variants<GaussianBlurPipeline> gaussian_blur_pipelines_;
471+
mutable Variants<GaussianBlurDecalPipeline> gaussian_blur_decal_pipelines_;
463472
mutable Variants<BorderMaskBlurPipeline> border_mask_blur_pipelines_;
464473
mutable Variants<MorphologyFilterPipeline> morphology_filter_pipelines_;
465474
mutable Variants<ColorMatrixColorFilterPipeline>

impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

Lines changed: 36 additions & 9 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

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)