Skip to content

Commit 9f32e03

Browse files
author
Jonah Williams
authored
[Impeller] Add support for specialization constants (III). (flutter#47765)
Reland of flutter/engine#47432 Also includes: flutter/engine#47617 flutter/engine#47637 Fixes the performance on iOS by removing blocking on compilation of shaders. From local testing this has identical before/after numbers. Additional, ensures that we don't unecessarily specialize vertex shaders and notes this restriction in the documentation. Adds support for Specialization constants to Impeller for our usage in the engine. A motivating example has been added in the impeller markdown docs. Fixes flutter#136210 Fixes flutter#119357 Investigating: flutter#138028
1 parent b67259c commit 9f32e03

File tree

64 files changed

+1247
-3983
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1247
-3983
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 8 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3136,42 +3136,13 @@ ORIGIN: ../../../flutter/impeller/entity/inline_pass_context.cc + ../../../flutt
31363136
ORIGIN: ../../../flutter/impeller/entity/inline_pass_context.h + ../../../flutter/LICENSE
31373137
ORIGIN: ../../../flutter/impeller/entity/render_target_cache.cc + ../../../flutter/LICENSE
31383138
ORIGIN: ../../../flutter/impeller/entity/render_target_cache.h + ../../../flutter/LICENSE
3139-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend.glsl + ../../../flutter/LICENSE
3139+
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend.frag + ../../../flutter/LICENSE
31403140
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend.vert + ../../../flutter/LICENSE
3141-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_color.frag + ../../../flutter/LICENSE
3142-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_colorburn.frag + ../../../flutter/LICENSE
3143-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_colordodge.frag + ../../../flutter/LICENSE
3144-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_darken.frag + ../../../flutter/LICENSE
3145-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_difference.frag + ../../../flutter/LICENSE
3146-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_exclusion.frag + ../../../flutter/LICENSE
3147-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_hardlight.frag + ../../../flutter/LICENSE
3148-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_hue.frag + ../../../flutter/LICENSE
3149-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_lighten.frag + ../../../flutter/LICENSE
3150-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_luminosity.frag + ../../../flutter/LICENSE
3151-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_multiply.frag + ../../../flutter/LICENSE
3152-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_overlay.frag + ../../../flutter/LICENSE
3153-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_saturation.frag + ../../../flutter/LICENSE
3154-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_screen.frag + ../../../flutter/LICENSE
3155-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_softlight.frag + ../../../flutter/LICENSE
31563141
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/blend.frag + ../../../flutter/LICENSE
31573142
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/blend.vert + ../../../flutter/LICENSE
3158-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend.glsl + ../../../flutter/LICENSE
3159-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend.vert + ../../../flutter/LICENSE
3160-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_color.frag + ../../../flutter/LICENSE
3161-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_colorburn.frag + ../../../flutter/LICENSE
3162-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_colordodge.frag + ../../../flutter/LICENSE
3163-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_darken.frag + ../../../flutter/LICENSE
3164-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_difference.frag + ../../../flutter/LICENSE
3165-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_exclusion.frag + ../../../flutter/LICENSE
3166-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_hardlight.frag + ../../../flutter/LICENSE
3167-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_hue.frag + ../../../flutter/LICENSE
3168-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_lighten.frag + ../../../flutter/LICENSE
3169-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_luminosity.frag + ../../../flutter/LICENSE
3170-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_multiply.frag + ../../../flutter/LICENSE
3171-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_overlay.frag + ../../../flutter/LICENSE
3172-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_saturation.frag + ../../../flutter/LICENSE
3173-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_screen.frag + ../../../flutter/LICENSE
3174-
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_softlight.frag + ../../../flutter/LICENSE
3143+
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/blend_select.glsl + ../../../flutter/LICENSE
3144+
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/framebuffer_blend.frag + ../../../flutter/LICENSE
3145+
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/framebuffer_blend.vert + ../../../flutter/LICENSE
31753146
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/porter_duff_blend.frag + ../../../flutter/LICENSE
31763147
ORIGIN: ../../../flutter/impeller/entity/shaders/blending/porter_duff_blend.vert + ../../../flutter/LICENSE
31773148
ORIGIN: ../../../flutter/impeller/entity/shaders/border_mask_blur.frag + ../../../flutter/LICENSE
@@ -5921,42 +5892,13 @@ FILE: ../../../flutter/impeller/entity/inline_pass_context.cc
59215892
FILE: ../../../flutter/impeller/entity/inline_pass_context.h
59225893
FILE: ../../../flutter/impeller/entity/render_target_cache.cc
59235894
FILE: ../../../flutter/impeller/entity/render_target_cache.h
5924-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend.glsl
5895+
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend.frag
59255896
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend.vert
5926-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_color.frag
5927-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_colorburn.frag
5928-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_colordodge.frag
5929-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_darken.frag
5930-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_difference.frag
5931-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_exclusion.frag
5932-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_hardlight.frag
5933-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_hue.frag
5934-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_lighten.frag
5935-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_luminosity.frag
5936-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_multiply.frag
5937-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_overlay.frag
5938-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_saturation.frag
5939-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_screen.frag
5940-
FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_softlight.frag
59415897
FILE: ../../../flutter/impeller/entity/shaders/blending/blend.frag
59425898
FILE: ../../../flutter/impeller/entity/shaders/blending/blend.vert
5943-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend.glsl
5944-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend.vert
5945-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_color.frag
5946-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_colorburn.frag
5947-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_colordodge.frag
5948-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_darken.frag
5949-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_difference.frag
5950-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_exclusion.frag
5951-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_hardlight.frag
5952-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_hue.frag
5953-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_lighten.frag
5954-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_luminosity.frag
5955-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_multiply.frag
5956-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_overlay.frag
5957-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_saturation.frag
5958-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_screen.frag
5959-
FILE: ../../../flutter/impeller/entity/shaders/blending/ios/framebuffer_blend_softlight.frag
5899+
FILE: ../../../flutter/impeller/entity/shaders/blending/blend_select.glsl
5900+
FILE: ../../../flutter/impeller/entity/shaders/blending/framebuffer_blend.frag
5901+
FILE: ../../../flutter/impeller/entity/shaders/blending/framebuffer_blend.vert
59605902
FILE: ../../../flutter/impeller/entity/shaders/blending/porter_duff_blend.frag
59615903
FILE: ../../../flutter/impeller/entity/shaders/blending/porter_duff_blend.vert
59625904
FILE: ../../../flutter/impeller/entity/shaders/border_mask_blur.frag

impeller/base/comparable.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,8 @@
88
#include <functional>
99
#include <map>
1010
#include <memory>
11-
#include <string>
1211
#include <type_traits>
1312

14-
#include "flutter/fml/hash_combine.h"
15-
#include "flutter/fml/macros.h"
16-
1713
namespace impeller {
1814

1915
struct UniqueID {
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Specialization Constants
2+
3+
A specialization constant is a named variable that is known to be constant at runtime but not when the shader is authored. These variables are bound to specific values when the shader is compiled on application start up and allow the backend to perform optimizations such as branch elimination and constant folding.
4+
5+
Specialization constants have two possible benefits when used in a shader:
6+
7+
* Improving performance, by removing branching and conditional code.
8+
* Code organization/size, by removing the number of shader source files required.
9+
10+
These goals are related: The number of shaders can be reduce by adding runtime branching to create more generic shaders. Alternatively, branching can be reduced by adding more specialized shader variants. Specialization constants provide a happy medium where the source files can be combined with branching but done so in a way that has no runtime cost.
11+
12+
## Example Usage
13+
14+
Consider the case of the "decal" texture sampling mode. This is implement via clamp-to-border with
15+
a border color set to transparent black. While this functionality is well supported on the Metal and
16+
Vulkan backends, the GLES backend needs to support devices that do not have this extension. As a
17+
result, the following code was used to conditionally decal:
18+
19+
```glsl
20+
// Decal sample if necessary.
21+
vec4 Sample(sampler2D sampler, vec2 coord) {
22+
#ifdef GLES
23+
return IPSampleDecal(sampler, coord)
24+
#else
25+
return texture(sampler, coord);
26+
#endif
27+
}
28+
```
29+
30+
This works great as long as we know that the GLES backend can never do the decal sample mode. This is also "free" as the ifdef branch is evaluated in the compiler. But eventually, we added a runtime check for decal mode as we need to support this on GLES. So the code turned into (approximately) the following:
31+
32+
```glsl
33+
#ifdef GLES
34+
uniform float supports_decal;
35+
#endif
36+
37+
// Decal sample if necessary.
38+
vec4 Sample(sampler2D sampler, vec2 coord) {
39+
#ifdef GLES
40+
if (supports_decal) {
41+
return texture(sampler, coord);
42+
}
43+
return IPSampleDecal(sampler, coord)
44+
#else
45+
return texture(sampler, coord);
46+
#endif
47+
}
48+
```
49+
50+
Now we've got decal support, but we've also got new problems:
51+
52+
* The code is actually quite messy. We have to track different uniform values depending on the backend.
53+
* The GLES backend is still paying some cost for branching, even though we "know" that decal is or isn't supported when the shader is compiled.
54+
55+
### Specialization constants to the rescue
56+
57+
Instead of using a runtime check, we can create a specialization constant that is set when compiling the
58+
shader. This constant will be `1` if decal is supported and `0` otherwise.
59+
60+
```glsl
61+
layout(constant_id = 0) const int supports_decal = 1;
62+
63+
vec4 Sample(sampler2D sampler, vec2 coord) {
64+
if (supports_decal) {
65+
return texture(sampler, coord);
66+
}
67+
return IPSampleDecal(sampler, coord)
68+
}
69+
70+
```
71+
72+
Immediately we realize a number of benefits:
73+
74+
* Code is the same across all backends
75+
* Runtime branching cost is removed as the branch is compiled out.
76+
77+
78+
## Implementation
79+
80+
Only 32bit ints are supported as const values and can be used to represent:
81+
82+
* true/false via 0/1.
83+
* function selection, such as advanced blends. The specialization value maps to a specific blend function. For example, 0 maps to screen and 1 to overlay via a giant if/else macro.
84+
* Only fragment shaders can be specialized. This limitation could be removed with more investment.
85+
86+
*AVOID* adding specialization constants for color values or anything more complex.
87+
88+
Specialization constants are provided to the CreateDefault argument in content_context.cc and aren't a
89+
part of variants. This is intentional: specialization constants shouldn't be used to create (potentially unlimited) runtime variants of a shader.
90+
91+
Backend specific information:
92+
* In the Metal backend, the specialization constants are mapped to a MTLFunctionConstantValues. See also: https://developer.apple.com/documentation/metal/using_function_specialization_to_build_pipeline_variants?language=objc
93+
* In the Vulkan backend, the specialization constants are mapped to VkSpecializationINfo. See also: https://blogs.igalia.com/itoral/2018/03/20/improving-shader-performance-with-vulkans-specialization-constants/
94+
* In the GLES backend, the SPIRV Cross compiler will generate defines named `#ifdef SPIRV_CROSS_CONSTANT_i`, where i is the index of constant. The Impeller runtime will insert `#define SPIRV_CROSS_CONSTANT_i` in the header of the shader.

impeller/entity/BUILD.gn

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,7 @@ impeller_shaders("entity_shaders") {
1515

1616
shaders = [
1717
"shaders/blending/advanced_blend.vert",
18-
"shaders/blending/advanced_blend_color.frag",
19-
"shaders/blending/advanced_blend_colorburn.frag",
20-
"shaders/blending/advanced_blend_colordodge.frag",
21-
"shaders/blending/advanced_blend_darken.frag",
22-
"shaders/blending/advanced_blend_difference.frag",
23-
"shaders/blending/advanced_blend_exclusion.frag",
24-
"shaders/blending/advanced_blend_hardlight.frag",
25-
"shaders/blending/advanced_blend_hue.frag",
26-
"shaders/blending/advanced_blend_lighten.frag",
27-
"shaders/blending/advanced_blend_luminosity.frag",
28-
"shaders/blending/advanced_blend_multiply.frag",
29-
"shaders/blending/advanced_blend_overlay.frag",
30-
"shaders/blending/advanced_blend_saturation.frag",
31-
"shaders/blending/advanced_blend_screen.frag",
32-
"shaders/blending/advanced_blend_softlight.frag",
18+
"shaders/blending/advanced_blend.frag",
3319
"shaders/blending/blend.frag",
3420
"shaders/blending/blend.vert",
3521
"shaders/border_mask_blur.frag",
@@ -115,22 +101,8 @@ impeller_shaders("framebuffer_blend_entity_shaders") {
115101
}
116102

117103
shaders = [
118-
"shaders/blending/ios/framebuffer_blend.vert",
119-
"shaders/blending/ios/framebuffer_blend_color.frag",
120-
"shaders/blending/ios/framebuffer_blend_colorburn.frag",
121-
"shaders/blending/ios/framebuffer_blend_colordodge.frag",
122-
"shaders/blending/ios/framebuffer_blend_darken.frag",
123-
"shaders/blending/ios/framebuffer_blend_difference.frag",
124-
"shaders/blending/ios/framebuffer_blend_exclusion.frag",
125-
"shaders/blending/ios/framebuffer_blend_hardlight.frag",
126-
"shaders/blending/ios/framebuffer_blend_hue.frag",
127-
"shaders/blending/ios/framebuffer_blend_lighten.frag",
128-
"shaders/blending/ios/framebuffer_blend_luminosity.frag",
129-
"shaders/blending/ios/framebuffer_blend_multiply.frag",
130-
"shaders/blending/ios/framebuffer_blend_overlay.frag",
131-
"shaders/blending/ios/framebuffer_blend_saturation.frag",
132-
"shaders/blending/ios/framebuffer_blend_screen.frag",
133-
"shaders/blending/ios/framebuffer_blend_softlight.frag",
104+
"shaders/blending/framebuffer_blend.vert",
105+
"shaders/blending/framebuffer_blend.frag",
134106
]
135107
}
136108

impeller/entity/contents/atlas_contents.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,6 @@ bool AtlasContents::Render(const ContentContext& renderer,
262262
dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal;
263263
dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal;
264264
}
265-
frag_info.supports_decal_sampler_address_mode =
266-
renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode();
267265
auto dst_sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler(
268266
dst_sampler_descriptor);
269267
FS::BindTextureSamplerDst(cmd, texture_, dst_sampler);

0 commit comments

Comments
 (0)