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

Commit efb606d

Browse files
author
Jonah Williams
authored
[CP] Add remap-sampler option to impellerc (#38228)
* [Impeller] order metal samplers according to declared order and not usage order (#38115) * [Impeller] order metal samplers according to declared order and not use order * ++ * always enabl remapping * Revert "always enabl remapping" This reverts commit 2fffb05. * ++ * add test * ++ * ++ * only run on mac * Fix sampler offsets (#38170) * [impeller] dont remap floats * ++ * Update fragment_shader_test.dart * ++: * ++
1 parent fdead7a commit efb606d

File tree

13 files changed

+218
-1
lines changed

13 files changed

+218
-1
lines changed

ci/licenses_golden/tool_signature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Signature: f6d8146c82d268e2e2549bf5019ebf07
1+
Signature: 9d0f7a4c4f53b80e33da848062bef937
22

impeller/compiler/compiler.cc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,45 @@ static CompilerBackend CreateMSLCompiler(const spirv_cross::ParsedIR& ir,
3535
sl_options.msl_version =
3636
spirv_cross::CompilerMSL::Options::make_msl_version(1, 2);
3737
sl_compiler->set_msl_options(sl_options);
38+
39+
// Set metal resource mappings to be consistent with location based mapping
40+
// used on other backends when creating fragment shaders. This doesn't seem
41+
// to work with the generated bindings for compute shaders, nor for certain
42+
// shaders in the flutter/engine tree.
43+
if (source_options.remap_samplers) {
44+
std::vector<uint32_t> sampler_offsets;
45+
ir.for_each_typed_id<spirv_cross::SPIRVariable>(
46+
[&](uint32_t, const spirv_cross::SPIRVariable& var) {
47+
if (var.storage != spv::StorageClassUniformConstant) {
48+
return;
49+
}
50+
const auto spir_type = sl_compiler->get_type(var.basetype);
51+
auto location = sl_compiler->get_decoration(
52+
var.self, spv::Decoration::DecorationLocation);
53+
if (spir_type.basetype ==
54+
spirv_cross::SPIRType::BaseType::SampledImage) {
55+
sampler_offsets.push_back(location);
56+
}
57+
});
58+
if (sampler_offsets.size() > 0) {
59+
auto start_offset =
60+
*std::min_element(sampler_offsets.begin(), sampler_offsets.end());
61+
for (auto offset : sampler_offsets) {
62+
sl_compiler->add_msl_resource_binding({
63+
.stage = spv::ExecutionModel::ExecutionModelFragment,
64+
.basetype = spirv_cross::SPIRType::BaseType::SampledImage,
65+
.binding = offset,
66+
.count = 1u,
67+
// A sampled image is both an image and a sampler, so both
68+
// offsets need to be set or depending on the partiular shader
69+
// the bindings may be incorrect.
70+
.msl_texture = offset - start_offset,
71+
.msl_sampler = offset - start_offset,
72+
});
73+
}
74+
}
75+
}
76+
3877
return CompilerBackend(sl_compiler);
3978
}
4079

impeller/compiler/impellerc_main.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ bool Main(const fml::CommandLine& command_line) {
7373
switches.source_file_name, options.type, options.source_language,
7474
switches.entry_point);
7575
options.json_format = switches.json_format;
76+
options.remap_samplers = switches.remap_samplers;
7677
options.gles_language_version = switches.gles_language_version;
7778

7879
Reflector::Options reflector_options;

impeller/compiler/source_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ struct SourceOptions {
2727
uint32_t gles_language_version = 100;
2828
std::vector<std::string> defines;
2929
bool json_format = false;
30+
bool remap_samplers = false;
3031

3132
SourceOptions();
3233

impeller/compiler/switches.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ void Switches::PrintHelp(std::ostream& stream) {
7171
stream << "[optional] --depfile=<depfile_path>" << std::endl;
7272
stream << "[optional] --gles-language-verision=<number>" << std::endl;
7373
stream << "[optional] --json" << std::endl;
74+
stream << "[optional] --remap-samplers (force metal sampler index to match "
75+
"declared order)"
76+
<< std::endl;
7477
}
7578

7679
Switches::Switches() = default;
@@ -125,6 +128,7 @@ Switches::Switches(const fml::CommandLine& command_line)
125128
command_line.GetOptionValueWithDefault("reflection-cc", "")),
126129
depfile_path(command_line.GetOptionValueWithDefault("depfile", "")),
127130
json_format(command_line.HasOption("json")),
131+
remap_samplers(command_line.HasOption("remap-samplers")),
128132
gles_language_version(
129133
stoi(command_line.GetOptionValueWithDefault("gles-language-version",
130134
"0"))),

impeller/compiler/switches.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct Switches {
3232
std::string depfile_path;
3333
std::vector<std::string> defines;
3434
bool json_format;
35+
bool remap_samplers;
3536
SourceLanguage source_language = SourceLanguage::kUnknown;
3637
uint32_t gles_language_version;
3738
std::string entry_point;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
// Declare samplers in different order than usage.
6+
uniform sampler2D textureA;
7+
uniform sampler2D textureB;
8+
9+
out vec4 frag_color;
10+
11+
void main() {
12+
vec4 sample_1 = texture(textureB, vec2(1.0));
13+
vec4 sample_2 = texture(textureA, vec2(1.0));
14+
frag_color = sample_1 + sample_2;
15+
}

impeller/tools/impeller.gni

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,13 @@ template("impellerc") {
233233
iplr = invoker.iplr
234234
}
235235
json = false
236+
remap_samplers = false
236237
if (defined(invoker.json) && invoker.json) {
237238
json = invoker.json
238239
}
240+
if (defined(invoker.remap_samplers) && invoker.remap_samplers) {
241+
remap_samplers = invoker.remap_samplers
242+
}
239243

240244
# Not needed on every path.
241245
not_needed([
@@ -248,6 +252,8 @@ template("impellerc") {
248252
# Optional: invoker.intermediates_subdir specifies the subdirectory in which
249253
# to put intermediates.
250254
# Optional: invoker.json Causes output format to be JSON instead of flatbuffer.
255+
# Optional: invoker.remap_samplers Output metal samplers according to
256+
# declaration order instead of usage order.
251257

252258
_impellerc(target_name) {
253259
sources = invoker.shaders
@@ -284,6 +290,9 @@ template("impellerc") {
284290
if (json) {
285291
args += [ "--json" ]
286292
}
293+
if (remap_samplers) {
294+
args += [ "--remap-samplers" ]
295+
}
287296

288297
if (sksl) {
289298
sl_intermediate =

lib/ui/fixtures/shaders/BUILD.gn

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,23 @@ if (enable_unittests) {
3333
json = true
3434
}
3535

36+
impellerc("sampler_order_fixture") {
37+
shaders = [
38+
"//flutter/impeller/fixtures/ordering/shader_with_samplers.frag",
39+
"//flutter/third_party/test_shaders/selman/glow_shader.frag",
40+
]
41+
shader_target_flag = "--runtime-stage-metal"
42+
intermediates_subdir = "iplr-remap"
43+
sl_file_extension = "iplr"
44+
iplr = true
45+
remap_samplers = true
46+
}
47+
3648
test_fixtures("fixtures") {
3749
deps = [
3850
":ink_sparkle",
3951
":ink_sparkle_web",
52+
":sampler_order_fixture",
4053
]
4154
fixtures = get_target_outputs(":ink_sparkle")
4255
dest = "$root_gen_dir/flutter/lib/ui"

testing/dart/fragment_shader_test.dart

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,34 @@ void main() async {
332332
shader.dispose();
333333
});
334334

335+
// This test can't rely on actual pixels rendered since it needs to run on a
336+
// metal shader on iOS. instead parse the source code.
337+
test('impellerc orders samplers in metal shader according to declaration and not usage', () async {
338+
if (!Platform.isMacOS) {
339+
return;
340+
}
341+
final Directory directory = shaderDirectory('iplr-remap');
342+
final String data = readAsStringLossy(File(path.join(directory.path, 'shader_with_samplers.frag.iplr')));
343+
344+
const String expected = 'texture2d<float> textureA [[texture(0)]],'
345+
' texture2d<float> textureB [[texture(1)]]';
346+
347+
expect(data, contains(expected));
348+
});
349+
350+
test('impellerc orders samplers in metal shader according to declaration and not usage in glow', () async {
351+
if (!Platform.isMacOS) {
352+
return;
353+
}
354+
final Directory directory = shaderDirectory('iplr-remap');
355+
final String data = readAsStringLossy(File(path.join(directory.path, 'glow_shader.frag.iplr')));
356+
357+
const String expected = 'texture2d<float> tInput [[texture(0)]], texture2d<float> tNoise [[texture(1)]], '
358+
'sampler tInputSmplr [[sampler(0)]], sampler tNoiseSmplr [[sampler(1)]]';
359+
360+
expect(data, contains(expected));
361+
});
362+
335363
// Test all supported GLSL ops. See lib/spirv/lib/src/constants.dart
336364
final Map<String, FragmentProgram> iplrSupportedGLSLOpShaders = await _loadShaderAssets(
337365
path.join('supported_glsl_op_shaders', 'iplr'),
@@ -484,3 +512,8 @@ Image _createBlueGreenImageSync() {
484512
picture.dispose();
485513
}
486514
}
515+
516+
// Ignore invalid utf8 since file is not actually text.
517+
String readAsStringLossy(File file) {
518+
return convert.utf8.decode(file.readAsBytesSync(), allowMalformed: true);
519+
}

0 commit comments

Comments
 (0)