Flutter Impeller
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>
6 #include "flutter/testing/testing.h"
7 #include "gtest/gtest.h"
13 
14 namespace impeller {
15 namespace compiler {
16 namespace testing {
17 
19  CompilerSuite,
21  ::testing::Values(TargetPlatform::kOpenGLES,
26  [](const ::testing::TestParamInfo<CompilerTest::ParamType>& info) {
27  return TargetPlatformToString(info.param);
28  });
29 
31  CompilerSuite,
33  ::testing::Values(TargetPlatform::kRuntimeStageMetal,
38  [](const ::testing::TestParamInfo<CompilerTest::ParamType>& info) {
39  return TargetPlatformToString(info.param);
40  });
41 
43  CompilerSuite,
45  ::testing::Values(TargetPlatform::kSkSL),
46  [](const ::testing::TestParamInfo<CompilerTest::ParamType>& info) {
47  return TargetPlatformToString(info.param);
48  });
49 
51  CompilerSuite,
53  ::testing::Values(TargetPlatform::kUnknown),
54  [](const ::testing::TestParamInfo<CompilerTest::ParamType>& info) {
55  return TargetPlatformToString(info.param);
56  });
57 
58 TEST(CompilerTest, Defines) {
59  std::shared_ptr<const fml::Mapping> fixture =
60  flutter::testing::OpenFixtureAsMapping("check_gles_definition.frag");
61 
62  SourceOptions options;
65  options.entry_point_name = "main";
67 
68  Reflector::Options reflector_options;
70  Compiler compiler = Compiler(fixture, options, reflector_options);
71 
72  // Should fail as the shader has a compilation error in it.
73  EXPECT_EQ(compiler.GetSPIRVAssembly(), nullptr);
74 
75  // Should succeed as the compilation error is ifdef'd out.
78  Compiler compiler_2 = Compiler(fixture, options, reflector_options);
79  EXPECT_NE(compiler_2.GetSPIRVAssembly(), nullptr);
80 }
81 
82 TEST(CompilerTest, DeprecatedUnflippedDefines) {
83  std::shared_ptr<const fml::Mapping> fixture =
84  flutter::testing::OpenFixtureAsMapping(
85  "check_gles_unflipped_definition.frag");
86 
87  SourceOptions options;
89  options.entry_point_name = "main";
91 
92  Reflector::Options reflector_options;
93 
94  // Test that IMPELLER_OPENGLES_UNFLIPPED_DEPRECATED is defined on
95  // TargetPlatform::kRuntimeStageGLES.
96  {
99  Compiler compiler = Compiler(fixture, options, reflector_options);
100  // Should fail as the shader has a compilation error in it.
101  EXPECT_EQ(compiler.GetSPIRVAssembly(), nullptr);
102  }
103 
104  // Test that IMPELLER_OPENGLES_UNFLIPPED_DEPRECATED is defined on
105  // TargetPlatform::kRuntimeStageGLES3.
106  {
109  Compiler compiler = Compiler(fixture, options, reflector_options);
110  // Should fail as the shader has a compilation error in it.
111  EXPECT_EQ(compiler.GetSPIRVAssembly(), nullptr);
112  }
113 
114  // Should succeed as the compilation error is ifdef'd out.
115  {
118  Compiler compiler = Compiler(fixture, options, reflector_options);
119  EXPECT_NE(compiler.GetSPIRVAssembly(), nullptr);
120  }
121 }
122 
123 TEST(CompilerTest, YFlipInjectionForGLESVertexShaders) {
124  // Compiles `fixture_name` for `platform` and returns the generated SL
125  // source. See https://github.com/flutter/flutter/issues/186554.
126  auto compile = [](const char* fixture_name, SourceType type,
127  TargetPlatform platform) -> std::string {
128  std::shared_ptr<fml::Mapping> fixture =
129  flutter::testing::OpenFixtureAsMapping(fixture_name);
130  FML_CHECK(fixture);
131 
132  SourceOptions options(fixture_name, type);
134  options.target_platform = platform;
135  options.working_directory = std::make_shared<fml::UniqueFD>(
136  flutter::testing::OpenFixturesDirectory());
137  options.entry_point_name = "main";
138 
139  Reflector::Options reflector_options;
140  reflector_options.target_platform = platform;
141  reflector_options.header_file_name = "y_flip_injection.h";
142  reflector_options.shader_name = "shader";
143 
144  Compiler compiler(fixture, options, reflector_options);
145  if (!compiler.IsValid()) {
146  return "";
147  }
148  auto sl = compiler.GetSLShaderSource();
149  if (!sl || !sl->GetMapping()) {
150  return "";
151  }
152  return std::string(reinterpret_cast<const char*>(sl->GetMapping()),
153  sl->GetSize());
154  };
155 
156  // GL vertex shader: gets both the declaration and the epilogue.
157  const std::string gl_vert = compile("sample.vert", SourceType::kVertexShader,
159  EXPECT_NE(gl_vert.find("uniform float _impeller_y_flip"), std::string::npos)
160  << "GLES vertex shader is missing the y-flip uniform declaration:\n"
161  << gl_vert;
162  EXPECT_NE(gl_vert.find("gl_Position.y *= _impeller_y_flip"),
163  std::string::npos)
164  << "GLES vertex shader is missing the y-flip epilogue:\n"
165  << gl_vert;
166 
167  // GL fragment shader: not injected.
168  const std::string gl_frag = compile(
170  EXPECT_EQ(gl_frag.find("_impeller_y_flip"), std::string::npos)
171  << "GLES fragment shader was unexpectedly injected:\n"
172  << gl_frag;
173 
174  // Metal vertex shader: not injected.
175  const std::string mtl_vert = compile("sample.vert", SourceType::kVertexShader,
177  EXPECT_EQ(mtl_vert.find("_impeller_y_flip"), std::string::npos)
178  << "Metal vertex shader was unexpectedly injected:\n"
179  << mtl_vert;
180 }
181 
182 TEST(CompilerTest, YFlipInjectionHandlesEarlyReturnsInGLESVertexShader) {
183  // `y_flip_early_return.vert` has an early `return` before main's implicit
184  // exit; the wrap-main injection must flip on both paths.
185  std::shared_ptr<fml::Mapping> fixture =
186  flutter::testing::OpenFixtureAsMapping("y_flip_early_return.vert");
187  FML_CHECK(fixture);
188 
189  SourceOptions options("y_flip_early_return.vert", SourceType::kVertexShader);
192  options.working_directory = std::make_shared<fml::UniqueFD>(
193  flutter::testing::OpenFixturesDirectory());
194  options.entry_point_name = "main";
195 
196  Reflector::Options reflector_options;
197  reflector_options.target_platform = TargetPlatform::kOpenGLES;
198  reflector_options.header_file_name = "y_flip_early_return.h";
199  reflector_options.shader_name = "shader";
200 
201  Compiler compiler(fixture, options, reflector_options);
202  ASSERT_TRUE(compiler.IsValid());
203  auto sl = compiler.GetSLShaderSource();
204  ASSERT_TRUE(sl && sl->GetMapping());
205  const std::string gl_vert(reinterpret_cast<const char*>(sl->GetMapping()),
206  sl->GetSize());
207 
208  EXPECT_NE(gl_vert.find("void _impeller_user_main("), std::string::npos)
209  << gl_vert;
210  EXPECT_NE(gl_vert.find("_impeller_user_main();"), std::string::npos)
211  << gl_vert;
212  EXPECT_NE(gl_vert.find("gl_Position.y *= _impeller_y_flip"),
213  std::string::npos)
214  << gl_vert;
215 
216  // Only the wrapper's `void main(` should remain after the rename.
217  const size_t first_main = gl_vert.find("\nvoid main(");
218  ASSERT_NE(first_main, std::string::npos);
219  EXPECT_EQ(gl_vert.find("\nvoid main(", first_main + 1), std::string::npos)
220  << gl_vert;
221 }
222 
223 TEST(CompilerTest, ShaderKindMatchingIsSuccessful) {
224  ASSERT_EQ(SourceTypeFromFileName("hello.vert"), SourceType::kVertexShader);
225  ASSERT_EQ(SourceTypeFromFileName("hello.frag"), SourceType::kFragmentShader);
226  ASSERT_EQ(SourceTypeFromFileName("hello.comp"), SourceType::kComputeShader);
227  ASSERT_EQ(SourceTypeFromFileName("hello.msl"), SourceType::kUnknown);
228  ASSERT_EQ(SourceTypeFromFileName("hello.glsl"), SourceType::kUnknown);
229 }
230 
231 TEST_P(CompilerTest, CanCompile) {
232  ASSERT_TRUE(CanCompileAndReflect("sample.vert"));
233  ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader));
234  ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader,
236 }
237 
238 TEST_P(CompilerTest, CanCompileHLSL) {
239  ASSERT_TRUE(CanCompileAndReflect(
240  "simple.vert.hlsl", SourceType::kVertexShader, SourceLanguage::kHLSL));
241 }
242 
243 TEST_P(CompilerTest, CanCompileHLSLWithMultipleStages) {
244  ASSERT_TRUE(CanCompileAndReflect("multiple_stages.hlsl",
246  SourceLanguage::kHLSL, "VertexShader"));
247  ASSERT_TRUE(CanCompileAndReflect("multiple_stages.hlsl",
249  SourceLanguage::kHLSL, "FragmentShader"));
250 }
251 
252 TEST_P(CompilerTest, CanCompileComputeShader) {
253  ASSERT_TRUE(CanCompileAndReflect("sample.comp", SourceType::kComputeShader,
254  SourceLanguage::kGLSL, "main"));
255 }
256 
257 TEST_P(CompilerTest, MustFailDueToExceedingResourcesLimit) {
258  ScopedValidationDisable disable_validation;
259  ASSERT_FALSE(
260  CanCompileAndReflect("resources_limit.vert", SourceType::kVertexShader));
261 }
262 
263 TEST_P(CompilerTest, MustFailDueToMultipleLocationPerStructMember) {
264  ScopedValidationDisable disable_validation;
265  ASSERT_FALSE(CanCompileAndReflect("struct_def_bug.vert"));
266 }
267 
268 TEST_P(CompilerTest, UniformBlockInstanceNameCanonicalizedForGL) {
269  if (!TargetPlatformIsOpenGL(GetParam())) {
270  GTEST_SKIP() << "Only GL targets lower uniform blocks to flat structs.";
271  }
272  // `mat2_test.frag` has `uniform Params { ... } uParams;`. Without
273  // canonicalization, BufferBindingsGLES cannot resolve `uParams.uMat2`.
274  ASSERT_TRUE(
275  CanCompileAndReflect("mat2_test.frag", SourceType::kFragmentShader));
276  auto sl_source = GetCompiler()->GetSLShaderSource();
277  ASSERT_NE(sl_source, nullptr);
278  const std::string source(
279  reinterpret_cast<const char*>(sl_source->GetMapping()),
280  sl_source->GetSize());
281  EXPECT_EQ(source.find("uParams."), std::string::npos) << source;
282  EXPECT_NE(source.find("_Params."), std::string::npos) << source;
283 }
284 
285 TEST_P(CompilerTest, BindingBaseForFragShader) {
286  if (!TargetPlatformIsVulkan(GetParam())) {
287  GTEST_SKIP();
288  }
289 
290  ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader));
291  ASSERT_TRUE(CanCompileAndReflect("sample.frag", SourceType::kFragmentShader));
292 
293  auto get_binding = [&](const char* fixture) -> uint32_t {
294  auto json_fd = GetReflectionJson(fixture);
295  nlohmann::json shader_json = nlohmann::json::parse(json_fd->GetMapping());
296  return shader_json["buffers"][0]["binding"].get<uint32_t>();
297  };
298 
299  auto vert_uniform_binding = get_binding("sample.vert");
300  auto frag_uniform_binding = get_binding("sample.frag");
301 
302  ASSERT_GT(frag_uniform_binding, vert_uniform_binding);
303 }
304 
305 namespace {
306 struct UniformInfo {
307  std::string uniform_name;
308  uint32_t location;
309  std::string type_name;
310  uint32_t columns;
311  uint32_t vec_size;
312 
313  static UniformInfo fromJson(const nlohmann::json& json) {
314  return {
315  .uniform_name = json["name"].get<std::string>(),
316  .location = json["location"].get<uint32_t>(),
317  .type_name = json["type"]["type_name"].get<std::string>(),
318  .columns = json["type"]["columns"].get<uint32_t>(),
319  .vec_size = json["type"]["vec_size"].get<uint32_t>(),
320  };
321  }
322 
323  static UniformInfo Sampler(const std::string& name, uint32_t location) {
324  return UniformInfo{
325  .uniform_name = name,
326  .location = location,
327  .type_name = "ShaderType::kSampledImage",
328  .columns = 1u,
329  .vec_size = 1u,
330  };
331  }
332  static UniformInfo Float(const std::string& name, uint32_t location) {
333  return FloatInfo(name, location, 1u, 1u);
334  }
335  static UniformInfo Vec2(const std::string& name, uint32_t location) {
336  return FloatInfo(name, location, 1u, 2u);
337  }
338  static UniformInfo Vec3(const std::string& name, uint32_t location) {
339  return FloatInfo(name, location, 1u, 3u);
340  }
341  static UniformInfo Vec4(const std::string& name, uint32_t location) {
342  return FloatInfo(name, location, 1u, 4u);
343  }
344  static UniformInfo Mat4(const std::string& name, uint32_t location) {
345  return FloatInfo(name, location, 4u, 4u);
346  }
347 
348  constexpr bool operator==(const UniformInfo& other) const {
349  return (uniform_name == other.uniform_name && //
350  location == other.location && //
351  type_name == other.type_name && //
352  columns == other.columns && //
353  vec_size == other.vec_size);
354  }
355 
356  private:
357  static UniformInfo FloatInfo(const std::string& name,
358  uint32_t location,
359  uint32_t columns,
360  uint32_t vec_size) {
361  return UniformInfo{
362  .uniform_name = name,
363  .location = location,
364  .type_name = "ShaderType::kFloat",
365  .columns = columns,
366  .vec_size = vec_size,
367  };
368  }
369 };
370 
371 inline std::ostream& operator<<(std::ostream& out, const UniformInfo& info) {
372  out << "UniformInfo {" << std::endl
373  << " uniform_name: " << info.uniform_name << std::endl
374  << " location: " << info.location << std::endl
375  << " type_name: " << info.type_name << std::endl
376  << " columns: " << info.columns << std::endl
377  << " vec_size: " << info.vec_size << std::endl
378  << "}";
379  return out;
380 }
381 } // namespace
382 
383 TEST_P(CompilerTestRuntime, UniformsAppearInJson) {
384  if (GetParam() == TargetPlatform::kRuntimeStageVulkan) {
385  // TODO(https://github.com/flutter/flutter/issues/182578): Investigate why
386  // this does not pass.
387  GTEST_SKIP() << "Not supported with Vulkan";
388  }
389 
390  ASSERT_TRUE(CanCompileAndReflect("sample_with_uniforms.frag",
393 
394  auto json_fd = GetReflectionJson("sample_with_uniforms.frag");
395  ASSERT_TRUE(json_fd);
396  nlohmann::json shader_json = nlohmann::json::parse(json_fd->GetMapping());
397  auto sampler_list = shader_json["sampled_images"];
398  auto float_list = shader_json["uniforms"];
399  ASSERT_EQ(sampler_list.size(), 2u);
400  ASSERT_EQ(float_list.size(), 6u);
401 
402  {
403  // clang-format off
404  std::array expected_infos = {
405  UniformInfo::Sampler("uFirstSampler", 1u),
406  UniformInfo::Sampler("uSampler", 7u),
407  };
408  // clang-format on
409  ASSERT_EQ(sampler_list.size(), expected_infos.size());
410  for (size_t i = 0; i < expected_infos.size(); i++) {
411  EXPECT_EQ(UniformInfo::fromJson(sampler_list[i]), expected_infos[i])
412  << "index: " << i;
413  }
414  }
415 
416  {
417  // clang-format off
418  std::array expected_infos = {
419  UniformInfo::Float("uFirstFloat", 0u),
420  UniformInfo::Float("uFloat", 2u),
421  UniformInfo::Vec2("uVec2", 3u),
422  UniformInfo::Vec3("uVec3", 4u),
423  UniformInfo::Vec4("uVec4", 5u),
424  UniformInfo::Mat4("uMat4", 6u),
425  };
426  // clang-format on
427  ASSERT_EQ(float_list.size(), expected_infos.size());
428  for (size_t i = 0; i < expected_infos.size(); i++) {
429  EXPECT_EQ(UniformInfo::fromJson(float_list[i]), expected_infos[i])
430  << "index: " << i;
431  }
432  }
433 }
434 
435 TEST_P(CompilerTestRuntime, PositionedUniformsAppearInJson) {
436  if (GetParam() == TargetPlatform::kRuntimeStageVulkan) {
437  // TODO(https://github.com/flutter/flutter/issues/182578): Investigate why
438  // this does not pass.
439  GTEST_SKIP() << "Not supported with Vulkan";
440  }
441 
442  ASSERT_TRUE(CanCompileAndReflect("sample_with_positioned_uniforms.frag",
445 
446  auto json_fd = GetReflectionJson("sample_with_positioned_uniforms.frag");
447  ASSERT_TRUE(json_fd);
448  nlohmann::json shader_json = nlohmann::json::parse(json_fd->GetMapping());
449  auto sampler_list = shader_json["sampled_images"];
450  auto float_list = shader_json["uniforms"];
451  ASSERT_EQ(sampler_list.size(), 3u);
452  ASSERT_EQ(float_list.size(), 7u);
453 
454  {
455  // clang-format off
456  std::array expected_infos = {
457  UniformInfo::Sampler("uSamplerNotPositioned1", 1u),
458  UniformInfo::Sampler("uSampler", 0u),
459  UniformInfo::Sampler("uSamplerNotPositioned2", 3u),
460  };
461  // clang-format on
462  ASSERT_EQ(sampler_list.size(), expected_infos.size());
463  for (size_t i = 0; i < expected_infos.size(); i++) {
464  EXPECT_EQ(UniformInfo::fromJson(sampler_list[i]), expected_infos[i])
465  << "index: " << i;
466  }
467  }
468 
469  {
470  // clang-format off
471  std::array expected_infos = {
472  UniformInfo::Float("uFloatNotPositioned1", 0u),
473  UniformInfo::Float("uFloat", 6u),
474  UniformInfo::Vec2("uVec2", 5u),
475  UniformInfo::Vec3("uVec3", 3u),
476  UniformInfo::Vec4("uVec4", 2u),
477  UniformInfo::Mat4("uMat4", 1u),
478  UniformInfo::Float("uFloatNotPositioned2", 2u),
479  };
480  // clang-format on
481  ASSERT_EQ(float_list.size(), expected_infos.size());
482  for (size_t i = 0; i < expected_infos.size(); i++) {
483  EXPECT_EQ(UniformInfo::fromJson(float_list[i]), expected_infos[i])
484  << "index: " << i;
485  }
486  }
487 }
488 
489 TEST_P(CompilerTest, UniformsHaveBindingAndSet) {
490  if (GetParam() == TargetPlatform::kSkSL) {
491  GTEST_SKIP() << "Not supported with SkSL";
492  }
493  ASSERT_TRUE(CanCompileAndReflect("sample_with_binding.vert",
495  ASSERT_TRUE(CanCompileAndReflect("sample.frag", SourceType::kFragmentShader));
496 
497  struct binding_and_set {
498  uint32_t binding;
499  uint32_t set;
500  };
501 
502  auto get_binding = [&](const char* fixture) -> binding_and_set {
503  auto json_fd = GetReflectionJson(fixture);
504  nlohmann::json shader_json = nlohmann::json::parse(json_fd->GetMapping());
505  uint32_t binding = shader_json["buffers"][0]["binding"].get<uint32_t>();
506  uint32_t set = shader_json["buffers"][0]["set"].get<uint32_t>();
507  return {binding, set};
508  };
509 
510  auto vert_uniform_binding = get_binding("sample_with_binding.vert");
511  auto frag_uniform_binding = get_binding("sample.frag");
512 
513  ASSERT_EQ(frag_uniform_binding.set, 0u);
514  ASSERT_EQ(vert_uniform_binding.set, 3u);
515  ASSERT_EQ(vert_uniform_binding.binding, 17u);
516 }
517 
518 TEST_P(CompilerTestSkSL, SkSLTextureLookUpOrderOfOperations) {
519  ASSERT_TRUE(
520  CanCompileAndReflect("texture_lookup.frag", SourceType::kFragmentShader));
521 
522  auto shader = GetShaderFile("texture_lookup.frag", GetParam());
523  std::string_view shader_mapping(
524  reinterpret_cast<const char*>(shader->GetMapping()), shader->GetSize());
525 
526  constexpr std::string_view expected =
527  "textureA.eval(textureA_size * ( vec2(1.0) + flutter_FragCoord.xy));";
528 
529  EXPECT_NE(shader_mapping.find(expected), std::string::npos);
530 }
531 
532 TEST_P(CompilerTestSkSL, CanCompileStructs) {
533  ASSERT_TRUE(CanCompileAndReflect("struct_internal.frag",
535 }
536 
537 TEST_P(CompilerTestSkSL, FailsToCompileDueToArrayInitializerWithConstants) {
538  auto expected_err =
539  "There was a compiler error: SkSL does not support array initializers: "
540  "array_initializer_with_constants.frag:6";
541 
542  EXPECT_EXIT(CanCompileAndReflect("array_initializer_with_constants.frag",
544  ::testing::ExitedWithCode(1), expected_err);
545 }
546 
547 TEST_P(CompilerTestSkSL, FailsToCompileDueToArrayInitializerWithVariables) {
548  auto expected_err =
549  "There was a compiler error: SkSL does not support array initializers: "
550  "array_initializer_with_variables.frag:12";
551 
552  EXPECT_EXIT(CanCompileAndReflect("array_initializer_with_variables.frag",
554  ::testing::ExitedWithCode(1), expected_err);
555 }
556 
557 TEST_P(CompilerTestSkSL, FailsToCompileDueToArrayAssignment) {
558  // Does not EXIT because the backend SkSL compiler doesn't detect the invalid
559  // SkSL. Returns false because the Impeller Compiler's post-compile validation
560  // fails.
561  ASSERT_FALSE(CanCompileAndReflect("array_assignment.frag",
563 
564  const Compiler* compiler = GetCompiler();
565  ASSERT_TRUE(compiler);
566  // Truncated error message.
567  ASSERT_STREQ(
568  compiler->GetErrorMessages().c_str(),
569  "\"array_assignment.frag\": \n"
570  "Compiled to invalid SkSL:\n"
571  " // This SkSL shader is autogenerated by spirv-cross.\n"
572  " \n"
573  " float4 flutter_FragCoord;\n"
574  " \n"
575  " vec4 frag_color;\n"
576  " \n"
577  "... (truncated 16 lines)\n"
578  "SkSL Error:\n"
579  " error: 12: initializers are not permitted on arrays (or structs "
580  "containing arrays)\n"
581  " float more_nums[2] = nums;\n"
582  " ^^^^\n"
583  " 1 error\n");
584  // Full error message.
585  ASSERT_STREQ(compiler->GetVerboseErrorMessages().c_str(),
586  "\"array_assignment.frag\": \n"
587  "Compiled to invalid SkSL:\n"
588  "// This SkSL shader is autogenerated by spirv-cross.\n"
589  "\n"
590  "float4 flutter_FragCoord;\n"
591  "\n"
592  "vec4 frag_color;\n"
593  "\n"
594  "void FLT_main()\n"
595  "{\n"
596  " float nums[2];\n"
597  " nums[0] = 1.0;\n"
598  " nums[1] = 0.5;\n"
599  " float more_nums[2] = nums;\n"
600  " frag_color = vec4(nums[0], nums[1], 1.0, 1.0);\n"
601  "}\n"
602  "\n"
603  "half4 main(float2 iFragCoord)\n"
604  "{\n"
605  " flutter_FragCoord = float4(iFragCoord, 0, 0);\n"
606  " FLT_main();\n"
607  " return frag_color;\n"
608  "}\n"
609  "\n"
610  "SkSL Error:\n"
611  "error: 12: initializers are not permitted on arrays (or "
612  "structs containing arrays)\n"
613  " float more_nums[2] = nums;\n"
614  " ^^^^\n"
615  "1 error\n"
616  "\n");
617 }
618 
619 TEST_P(CompilerTestSkSL, CompilesWithValidArrayInitialization) {
620  ASSERT_TRUE(
621  CanCompileAndReflect("array_initialization_without_initializer.frag",
623 }
624 
625 TEST_P(CompilerTestRuntime, Mat2Reflection) {
626  if (GetParam() == TargetPlatform::kSkSL) {
627  GTEST_SKIP() << "Not supported with SkSL";
628  }
629 
630  ASSERT_TRUE(CanCompileAndReflect(
632 
633  std::unique_ptr<fml::FileMapping> json_fd =
634  GetReflectionJson("mat2_test.frag");
635  ASSERT_TRUE(json_fd);
636  nlohmann::json shader_json = nlohmann::json::parse(json_fd->GetMapping());
637  nlohmann::json::value_type buffers = shader_json["buffers"];
638 
639  // uParams should be in buffers.
640  ASSERT_GE(buffers.size(), 1u);
641  nlohmann::json::value_type uParams = buffers[0];
642  EXPECT_EQ(uParams["name"], "Params");
643 
644  nlohmann::json::value_type members = uParams["type"]["members"];
645  // We expect 1 member (for the mat2) which is a Point (vec2) with array
646  // size 2.
647  ASSERT_EQ(members.size(), 1u);
648 
649  nlohmann::json::value_type mat2Member = members[0];
650 
651  // Should be Mat2 (vec2)
652  EXPECT_EQ(mat2Member["type"], "Mat2");
653 
654  // Size 8 bytes (vec2)
655  EXPECT_EQ(mat2Member["size"], 8u);
656 
657  // Byte length should be total array size (stride * count)
658  // Stride 16 * 2 = 32.
659  EXPECT_EQ(mat2Member["byte_length"], 32u);
660 
661  // Array elements should be 2 (columns).
662  EXPECT_EQ(mat2Member["array_elements"], 2u);
663 
664  // Offset 0
665  EXPECT_EQ(mat2Member["offset"], 0u);
666 }
667 
668 TEST_P(CompilerTestUnknownPlatform, MustFailDueToUnknownPlatform) {
669  ASSERT_FALSE(
670  CanCompileAndReflect("sample.frag", SourceType::kFragmentShader));
671 }
672 
673 } // namespace testing
674 } // namespace compiler
675 } // namespace impeller
std::string GetVerboseErrorMessages() const
Definition: compiler.cc:705
std::shared_ptr< fml::Mapping > GetSPIRVAssembly() const
Definition: compiler.cc:683
std::shared_ptr< fml::Mapping > GetSLShaderSource() const
Definition: compiler.cc:687
std::string GetErrorMessages() const
Definition: compiler.cc:701
uint32_t vec_size
std::string type_name
uint32_t columns
std::string uniform_name
uint32_t location
INSTANTIATE_TEST_SUITE_P(CompilerSuite, CompilerTest, ::testing::Values(TargetPlatform::kOpenGLES, TargetPlatform::kOpenGLDesktop, TargetPlatform::kMetalDesktop, TargetPlatform::kMetalIOS, TargetPlatform::kVulkan), [](const ::testing::TestParamInfo< CompilerTest::ParamType > &info) { return TargetPlatformToString(info.param);})
TEST_P(CompilerTest, CanCompile)
TEST(CompilerTest, Defines)
std::string TargetPlatformToString(TargetPlatform platform)
Definition: types.cc:62
SourceType SourceTypeFromFileName(const std::filesystem::path &file_name)
Definition: types.cc:17
bool TargetPlatformIsOpenGL(TargetPlatform platform)
Definition: types.cc:239
bool TargetPlatformIsVulkan(TargetPlatform platform)
Definition: types.cc:277
std::ostream & operator<<(std::ostream &out, const impeller::Arc &a)
Definition: arc.h:141
std::shared_ptr< fml::UniqueFD > working_directory