1// Copyright 2014 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
5import 'package:flutter_tools/src/base/file_system.dart';
6import 'package:flutter_tools/src/base/logger.dart';
7import 'package:flutter_tools/src/build_info.dart';
8import 'package:flutter_tools/src/build_system/tools/shader_compiler.dart';
9import 'package:flutter_tools/src/globals.dart' as globals;
10
11import '../src/common.dart';
12import '../src/context.dart';
13
14void main() {
15 late BufferLogger logger;
16
17 setUp(() {
18 logger = BufferLogger.test();
19 });
20
21 Future<void> testCompileShader(String source) async {
22 final Directory tmpDir = globals.fs.systemTempDirectory.createTempSync('shader_compiler_test.');
23 final File file = tmpDir.childFile('test_shader.frag')..writeAsStringSync(source);
24 final shaderCompiler = ShaderCompiler(
25 processManager: globals.processManager,
26 logger: logger,
27 fileSystem: globals.fs,
28 artifacts: globals.artifacts!,
29 );
30 await shaderCompiler.compileShader(
31 input: file,
32 outputPath: tmpDir.childFile('test_shader.frag.out').path,
33 targetPlatform: TargetPlatform.tester,
34 );
35 }
36
37 testUsingContext('impellerc .iplr output has correct permissions', () async {
38 if (globals.platform.isWindows) {
39 return;
40 }
41
42 final String flutterRoot = getFlutterRoot();
43 final String inkSparklePath = globals.fs.path.join(
44 flutterRoot,
45 'packages',
46 'flutter',
47 'lib',
48 'src',
49 'material',
50 'shaders',
51 'ink_sparkle.frag',
52 );
53 final Directory tmpDir = globals.fs.systemTempDirectory.createTempSync('shader_compiler_test.');
54 final String inkSparkleOutputPath = globals.fs.path.join(tmpDir.path, 'ink_sparkle.frag');
55
56 final shaderCompiler = ShaderCompiler(
57 processManager: globals.processManager,
58 logger: logger,
59 fileSystem: globals.fs,
60 artifacts: globals.artifacts!,
61 );
62 final bool compileResult = await shaderCompiler.compileShader(
63 input: globals.fs.file(inkSparklePath),
64 outputPath: inkSparkleOutputPath,
65 targetPlatform: TargetPlatform.tester,
66 );
67 final File resultFile = globals.fs.file(inkSparkleOutputPath);
68
69 expect(compileResult, true);
70 expect(resultFile.existsSync(), true);
71
72 final int expectedMode = int.parse('644', radix: 8);
73 expect(resultFile.statSync().mode & expectedMode, equals(expectedMode));
74 });
75
76 testUsingContext('Compilation error with in storage', () async {
77 const kShaderWithInput = '''
78in float foo;
79
80out vec4 fragColor;
81
82void main() {
83 fragColor = vec4(1.0, 0.0, 0.0, 1.0);
84}
85''';
86
87 expect(
88 () => testCompileShader(kShaderWithInput),
89 throwsA(
90 isA<ShaderCompilerException>().having(
91 (ShaderCompilerException exception) => exception.message,
92 'message',
93 contains('SkSL does not support inputs'),
94 ),
95 ),
96 );
97 });
98
99 testUsingContext('Compilation error with UBO', () async {
100 const kShaderWithInput = '''
101uniform Data {
102 vec4 foo;
103} data;
104
105out vec4 fragColor;
106
107void main() {
108 fragColor = data.foo;
109}
110''';
111
112 expect(
113 () => testCompileShader(kShaderWithInput),
114 throwsA(
115 isA<ShaderCompilerException>().having(
116 (ShaderCompilerException exception) => exception.message,
117 'message',
118 contains('SkSL does not support UBOs or SSBOs'),
119 ),
120 ),
121 );
122 });
123
124 testUsingContext(
125 'Compilation error with texture arguments besides position or sampler',
126 () async {
127 const kShaderWithInput = '''
128uniform sampler2D tex;
129
130out vec4 fragColor;
131
132void main() {
133 fragColor = texture(tex, vec2(0.5, 0.3), 0.5);
134}
135''';
136
137 expect(
138 () => testCompileShader(kShaderWithInput),
139 throwsA(
140 isA<ShaderCompilerException>().having(
141 (ShaderCompilerException exception) => exception.message,
142 'message',
143 contains('Only sampler and position arguments are supported in texture() calls'),
144 ),
145 ),
146 );
147 },
148 );
149
150 testUsingContext('Compilation error with uint8 uniforms', () async {
151 const kShaderWithInput = '''
152#version 310 es
153
154layout(location = 0) uniform uint foo;
155layout(location = 0) out vec4 fragColor;
156
157void main() {}
158''';
159
160 expect(
161 () => testCompileShader(kShaderWithInput),
162 throwsA(
163 isA<ShaderCompilerException>().having(
164 (ShaderCompilerException exception) => exception.message,
165 'message',
166 contains('SkSL does not support unsigned integers'),
167 ),
168 ),
169 );
170 });
171}
172