Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
compiler_unittests.cc
Go to the documentation of this file.
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 <cstring>
7#include "gtest/gtest.h"
13
14namespace impeller {
15namespace compiler {
16namespace testing {
17
18TEST(CompilerTest, Defines) {
19 std::shared_ptr<const fml::Mapping> fixture =
20 flutter::testing::OpenFixtureAsMapping("check_gles_definition.frag");
21
22 SourceOptions options;
25 options.entry_point_name = "main";
27
28 Reflector::Options reflector_options;
30 Compiler compiler = Compiler(fixture, options, reflector_options);
31
32 // Should fail as the shader has a compilation error in it.
33 EXPECT_EQ(compiler.GetSPIRVAssembly(), nullptr);
34
35 // Should succeed as the compilation error is ifdef'd out.
38 Compiler compiler_2 = Compiler(fixture, options, reflector_options);
39 EXPECT_NE(compiler_2.GetSPIRVAssembly(), nullptr);
40}
41
42TEST(CompilerTest, ShaderKindMatchingIsSuccessful) {
43 ASSERT_EQ(SourceTypeFromFileName("hello.vert"), SourceType::kVertexShader);
45 ASSERT_EQ(SourceTypeFromFileName("hello.comp"), SourceType::kComputeShader);
46 ASSERT_EQ(SourceTypeFromFileName("hello.msl"), SourceType::kUnknown);
47 ASSERT_EQ(SourceTypeFromFileName("hello.glsl"), SourceType::kUnknown);
48}
49
50TEST_P(CompilerTest, CanCompile) {
51 if (GetParam() == TargetPlatform::kSkSL) {
52 GTEST_SKIP() << "Not supported with SkSL";
53 }
54 ASSERT_TRUE(CanCompileAndReflect("sample.vert"));
55 ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader));
56 ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader,
58}
59
60TEST_P(CompilerTest, CanCompileHLSL) {
61 if (GetParam() == TargetPlatform::kSkSL) {
62 GTEST_SKIP() << "Not supported with SkSL";
63 }
64 ASSERT_TRUE(CanCompileAndReflect(
66}
67
68TEST_P(CompilerTest, CanCompileHLSLWithMultipleStages) {
69 if (GetParam() == TargetPlatform::kSkSL) {
70 GTEST_SKIP() << "Not supported with SkSL";
71 }
72 ASSERT_TRUE(CanCompileAndReflect("multiple_stages.hlsl",
74 SourceLanguage::kHLSL, "VertexShader"));
75 ASSERT_TRUE(CanCompileAndReflect("multiple_stages.hlsl",
77 SourceLanguage::kHLSL, "FragmentShader"));
78}
79
80TEST_P(CompilerTest, CanCompileComputeShader) {
81 if (!TargetPlatformIsMetal(GetParam())) {
82 GTEST_SKIP()
83 << "Only enabled on Metal backends till ES 3.2 support is added.";
84 }
85 ASSERT_TRUE(CanCompileAndReflect("sample.comp"));
86 ASSERT_TRUE(CanCompileAndReflect("sample.comp", SourceType::kComputeShader));
87}
88
89TEST_P(CompilerTest, MustFailDueToExceedingResourcesLimit) {
90 if (GetParam() == TargetPlatform::kSkSL) {
91 GTEST_SKIP() << "Not supported with SkSL";
92 }
93 ScopedValidationDisable disable_validation;
94 ASSERT_FALSE(
95 CanCompileAndReflect("resources_limit.vert", SourceType::kVertexShader));
96}
97
98TEST_P(CompilerTest, MustFailDueToMultipleLocationPerStructMember) {
99 if (GetParam() == TargetPlatform::kSkSL) {
100 GTEST_SKIP() << "Not supported with SkSL";
101 }
102 ScopedValidationDisable disable_validation;
103 ASSERT_FALSE(CanCompileAndReflect("struct_def_bug.vert"));
104}
105
106TEST_P(CompilerTest, BindingBaseForFragShader) {
107 if (!TargetPlatformIsVulkan(GetParam())) {
108 GTEST_SKIP();
109 }
110
111 ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader));
112 ASSERT_TRUE(CanCompileAndReflect("sample.frag", SourceType::kFragmentShader));
113
114 auto get_binding = [&](const char* fixture) -> uint32_t {
115 auto json_fd = GetReflectionJson(fixture);
116 nlohmann::json shader_json = nlohmann::json::parse(json_fd->GetMapping());
117 return shader_json["buffers"][0]["binding"].get<uint32_t>();
118 };
119
120 auto vert_uniform_binding = get_binding("sample.vert");
121 auto frag_uniform_binding = get_binding("sample.frag");
122
123 ASSERT_GT(frag_uniform_binding, vert_uniform_binding);
124}
125
126namespace {
127struct UniformInfo {
128 std::string uniform_name;
129 uint32_t location;
130 std::string type_name;
131 uint32_t columns;
132 uint32_t vec_size;
133
134 static UniformInfo fromJson(const nlohmann::json& json) {
135 return {
136 .uniform_name = json["name"].get<std::string>(),
137 .location = json["location"].get<uint32_t>(),
138 .type_name = json["type"]["type_name"].get<std::string>(),
139 .columns = json["type"]["columns"].get<uint32_t>(),
140 .vec_size = json["type"]["vec_size"].get<uint32_t>(),
141 };
142 }
143
144 static UniformInfo Sampler(const std::string& name, uint32_t location) {
145 return UniformInfo{
146 .uniform_name = name,
147 .location = location,
148 .type_name = "ShaderType::kSampledImage",
149 .columns = 1u,
150 .vec_size = 1u,
151 };
152 }
153 static UniformInfo Float(const std::string& name, uint32_t location) {
154 return FloatInfo(name, location, 1u, 1u);
155 }
156 static UniformInfo Vec2(const std::string& name, uint32_t location) {
157 return FloatInfo(name, location, 1u, 2u);
158 }
159 static UniformInfo Vec3(const std::string& name, uint32_t location) {
160 return FloatInfo(name, location, 1u, 3u);
161 }
162 static UniformInfo Vec4(const std::string& name, uint32_t location) {
163 return FloatInfo(name, location, 1u, 4u);
164 }
165 static UniformInfo Mat4(const std::string& name, uint32_t location) {
166 return FloatInfo(name, location, 4u, 4u);
167 }
168
169 constexpr bool operator==(const UniformInfo& other) const {
170 return (uniform_name == other.uniform_name && //
171 location == other.location && //
172 type_name == other.type_name && //
173 columns == other.columns && //
174 vec_size == other.vec_size);
175 }
176
177 private:
178 static UniformInfo FloatInfo(const std::string& name,
179 uint32_t location,
180 uint32_t columns,
181 uint32_t vec_size) {
182 return UniformInfo{
183 .uniform_name = name,
184 .location = location,
185 .type_name = "ShaderType::kFloat",
186 .columns = columns,
187 .vec_size = vec_size,
188 };
189 }
190};
191
192inline std::ostream& operator<<(std::ostream& out, const UniformInfo& info) {
193 out << "UniformInfo {" << std::endl
194 << " uniform_name: " << info.uniform_name << std::endl
195 << " location: " << info.location << std::endl
196 << " type_name: " << info.type_name << std::endl
197 << " columns: " << info.columns << std::endl
198 << " vec_size: " << info.vec_size << std::endl
199 << "}";
200 return out;
201}
202} // namespace
203
204TEST_P(CompilerTestRuntime, UniformsAppearInJson) {
205 ASSERT_TRUE(CanCompileAndReflect("sample_with_uniforms.frag",
208
209 auto json_fd = GetReflectionJson("sample_with_uniforms.frag");
210 ASSERT_TRUE(json_fd);
211 nlohmann::json shader_json = nlohmann::json::parse(json_fd->GetMapping());
212 auto sampler_list = shader_json["sampled_images"];
213 auto float_list = shader_json["uniforms"];
214 ASSERT_EQ(sampler_list.size(), 2u);
215 ASSERT_EQ(float_list.size(), 6u);
216
217 {
218 // clang-format off
219 std::array expected_infos = {
220 UniformInfo::Sampler("uFirstSampler", 1u),
221 UniformInfo::Sampler("uSampler", 7u),
222 };
223 // clang-format on
224 ASSERT_EQ(sampler_list.size(), expected_infos.size());
225 for (size_t i = 0; i < expected_infos.size(); i++) {
226 EXPECT_EQ(UniformInfo::fromJson(sampler_list[i]), expected_infos[i])
227 << "index: " << i;
228 }
229 }
230
231 {
232 // clang-format off
233 std::array expected_infos = {
234 UniformInfo::Float("uFirstFloat", 0u),
235 UniformInfo::Float("uFloat", 2u),
236 UniformInfo::Vec2("uVec2", 3u),
237 UniformInfo::Vec3("uVec3", 4u),
238 UniformInfo::Vec4("uVec4", 5u),
239 UniformInfo::Mat4("uMat4", 6u),
240 };
241 // clang-format on
242 ASSERT_EQ(float_list.size(), expected_infos.size());
243 for (size_t i = 0; i < expected_infos.size(); i++) {
244 EXPECT_EQ(UniformInfo::fromJson(float_list[i]), expected_infos[i])
245 << "index: " << i;
246 }
247 }
248}
249
250TEST_P(CompilerTestRuntime, PositionedUniformsAppearInJson) {
251 ASSERT_TRUE(CanCompileAndReflect("sample_with_positioned_uniforms.frag",
254
255 auto json_fd = GetReflectionJson("sample_with_positioned_uniforms.frag");
256 ASSERT_TRUE(json_fd);
257 nlohmann::json shader_json = nlohmann::json::parse(json_fd->GetMapping());
258 auto sampler_list = shader_json["sampled_images"];
259 auto float_list = shader_json["uniforms"];
260 ASSERT_EQ(sampler_list.size(), 3u);
261 ASSERT_EQ(float_list.size(), 7u);
262
263 {
264 // clang-format off
265 std::array expected_infos = {
266 UniformInfo::Sampler("uSamplerNotPositioned1", 1u),
267 UniformInfo::Sampler("uSampler", 0u),
268 UniformInfo::Sampler("uSamplerNotPositioned2", 3u),
269 };
270 // clang-format on
271 ASSERT_EQ(sampler_list.size(), expected_infos.size());
272 for (size_t i = 0; i < expected_infos.size(); i++) {
273 EXPECT_EQ(UniformInfo::fromJson(sampler_list[i]), expected_infos[i])
274 << "index: " << i;
275 }
276 }
277
278 {
279 // clang-format off
280 std::array expected_infos = {
281 UniformInfo::Float("uFloatNotPositioned1", 0u),
282 UniformInfo::Float("uFloat", 6u),
283 UniformInfo::Vec2("uVec2", 5u),
284 UniformInfo::Vec3("uVec3", 3u),
285 UniformInfo::Vec4("uVec4", 2u),
286 UniformInfo::Mat4("uMat4", 1u),
287 UniformInfo::Float("uFloatNotPositioned2", 2u),
288 };
289 // clang-format on
290 ASSERT_EQ(float_list.size(), expected_infos.size());
291 for (size_t i = 0; i < expected_infos.size(); i++) {
292 EXPECT_EQ(UniformInfo::fromJson(float_list[i]), expected_infos[i])
293 << "index: " << i;
294 }
295 }
296}
297
298TEST_P(CompilerTest, UniformsHaveBindingAndSet) {
299 if (GetParam() == TargetPlatform::kSkSL) {
300 GTEST_SKIP() << "Not supported with SkSL";
301 }
302 ASSERT_TRUE(CanCompileAndReflect("sample_with_binding.vert",
304 ASSERT_TRUE(CanCompileAndReflect("sample.frag", SourceType::kFragmentShader));
305
306 struct binding_and_set {
307 uint32_t binding;
308 uint32_t set;
309 };
310
311 auto get_binding = [&](const char* fixture) -> binding_and_set {
312 auto json_fd = GetReflectionJson(fixture);
313 nlohmann::json shader_json = nlohmann::json::parse(json_fd->GetMapping());
314 uint32_t binding = shader_json["buffers"][0]["binding"].get<uint32_t>();
315 uint32_t set = shader_json["buffers"][0]["set"].get<uint32_t>();
316 return {binding, set};
317 };
318
319 auto vert_uniform_binding = get_binding("sample_with_binding.vert");
320 auto frag_uniform_binding = get_binding("sample.frag");
321
322 ASSERT_EQ(frag_uniform_binding.set, 0u);
323 ASSERT_EQ(vert_uniform_binding.set, 3u);
324 ASSERT_EQ(vert_uniform_binding.binding, 17u);
325}
326
327TEST_P(CompilerTestSkSL, SkSLTextureLookUpOrderOfOperations) {
328 ASSERT_TRUE(
329 CanCompileAndReflect("texture_lookup.frag", SourceType::kFragmentShader));
330
331 auto shader = GetShaderFile("texture_lookup.frag", GetParam());
332 std::string_view shader_mapping(
333 reinterpret_cast<const char*>(shader->GetMapping()), shader->GetSize());
334
335 constexpr std::string_view expected =
336 "textureA.eval(textureA_size * ( vec2(1.0) + flutter_FragCoord.xy));";
337
338 EXPECT_NE(shader_mapping.find(expected), std::string::npos);
339}
340
341TEST_P(CompilerTestSkSL, CanCompileStructs) {
342 ASSERT_TRUE(CanCompileAndReflect("struct_internal.frag",
344}
345
346#define INSTANTIATE_TARGET_PLATFORM_TEST_SUITE_P(suite_name) \
347 INSTANTIATE_TEST_SUITE_P( \
348 suite_name, CompilerTest, \
349 ::testing::Values(TargetPlatform::kOpenGLES, \
350 TargetPlatform::kOpenGLDesktop, \
351 TargetPlatform::kMetalDesktop, \
352 TargetPlatform::kMetalIOS, TargetPlatform::kSkSL), \
353 [](const ::testing::TestParamInfo<CompilerTest::ParamType>& info) { \
354 return TargetPlatformToString(info.param); \
355 });
356
358
359#define INSTANTIATE_RUNTIME_TARGET_PLATFORM_TEST_SUITE_P(suite_name) \
360 INSTANTIATE_TEST_SUITE_P( \
361 suite_name, CompilerTestRuntime, \
362 ::testing::Values(TargetPlatform::kRuntimeStageMetal), \
363 [](const ::testing::TestParamInfo<CompilerTest::ParamType>& info) { \
364 return TargetPlatformToString(info.param); \
365 });
366
368
369#define INSTANTIATE_SKSL_TARGET_PLATFORM_TEST_SUITE_P(suite_name) \
370 INSTANTIATE_TEST_SUITE_P( \
371 suite_name, CompilerTestSkSL, ::testing::Values(TargetPlatform::kSkSL), \
372 [](const ::testing::TestParamInfo<CompilerTest::ParamType>& info) { \
373 return TargetPlatformToString(info.param); \
374 });
375
377
378} // namespace testing
379} // namespace compiler
380} // namespace impeller
std::shared_ptr< fml::Mapping > GetSPIRVAssembly() const
Definition compiler.cc:486
#define INSTANTIATE_SKSL_TARGET_PLATFORM_TEST_SUITE_P(suite_name)
uint32_t vec_size
#define INSTANTIATE_RUNTIME_TARGET_PLATFORM_TEST_SUITE_P(suite_name)
std::string type_name
uint32_t columns
#define INSTANTIATE_TARGET_PLATFORM_TEST_SUITE_P(suite_name)
std::string uniform_name
uint32_t location
bool operator==(const FlutterPoint &a, const FlutterPoint &b)
std::ostream & operator<<(std::ostream &out, const FlutterPoint &point)
const char * name
Definition fuchsia.cc:49
std::unique_ptr< fml::Mapping > OpenFixtureAsMapping(const std::string &fixture_name)
Opens a fixture of the given file name and returns a mapping to its contents.
Definition testing.cc:58
std::function< ProfileSample(void)> Sampler
Sampler is run during SamplingProfiler::SampleRepeatedly. Each platform should implement its version ...
TEST_P(CompilerTest, CanCompile)
TEST(CompilerTest, Defines)
SourceType SourceTypeFromFileName(const std::filesystem::path &file_name)
Definition types.cc:17
bool TargetPlatformIsMetal(TargetPlatform platform)
Definition types.cc:277
bool TargetPlatformIsVulkan(TargetPlatform platform)
Definition types.cc:296