Flutter Impeller
shader_bundle_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 "gtest/gtest.h"
7 
8 #include "flutter/testing/testing.h"
11 #include "impeller/shader_bundle/shader_bundle_flatbuffers.h"
12 
13 namespace impeller {
14 namespace compiler {
15 namespace testing {
16 
17 const std::string kUnlitFragmentBundleConfig =
18  "\"UnlitFragment\": {\"type\": \"fragment\", \"file\": "
19  "\"shaders/flutter_gpu_unlit.frag\"}";
20 const std::string kUnlitVertexBundleConfig =
21  "\"UnlitVertex\": {\"type\": \"vertex\", \"file\": "
22  "\"shaders/flutter_gpu_unlit.vert\"}";
23 
24 TEST(ShaderBundleTest, ParseShaderBundleConfigFailsForInvalidJSON) {
25  std::string bundle = "";
26  std::stringstream error;
27  auto result = ParseShaderBundleConfig(bundle, error);
28  ASSERT_FALSE(result.has_value());
29  ASSERT_STREQ(error.str().c_str(),
30  "The shader bundle is not a valid JSON object.\n");
31 }
32 
33 TEST(ShaderBundleTest, ParseShaderBundleConfigFailsWhenEntryNotObject) {
34  std::string bundle = "{\"UnlitVertex\": []}";
35  std::stringstream error;
36  auto result = ParseShaderBundleConfig(bundle, error);
37  ASSERT_FALSE(result.has_value());
38  ASSERT_STREQ(
39  error.str().c_str(),
40  "Invalid shader entry \"UnlitVertex\": Entry is not a JSON object.\n");
41 }
42 
43 TEST(ShaderBundleTest, ParseShaderBundleConfigFailsWhenMissingFile) {
44  std::string bundle = "{\"UnlitVertex\": {\"type\": \"vertex\"}}";
45  std::stringstream error;
46  auto result = ParseShaderBundleConfig(bundle, error);
47  ASSERT_FALSE(result.has_value());
48  ASSERT_STREQ(error.str().c_str(),
49  "Invalid shader entry \"UnlitVertex\": Missing required "
50  "\"file\" field.\n");
51 }
52 
53 TEST(ShaderBundleTest, ParseShaderBundleConfigFailsWhenMissingType) {
54  std::string bundle =
55  "{\"UnlitVertex\": {\"file\": \"shaders/flutter_gpu_unlit.vert\"}}";
56  std::stringstream error;
57  auto result = ParseShaderBundleConfig(bundle, error);
58  ASSERT_FALSE(result.has_value());
59  ASSERT_STREQ(error.str().c_str(),
60  "Invalid shader entry \"UnlitVertex\": Missing required "
61  "\"type\" field.\n");
62 }
63 
64 TEST(ShaderBundleTest, ParseShaderBundleConfigFailsForInvalidType) {
65  std::string bundle =
66  "{\"UnlitVertex\": {\"type\": \"invalid\", \"file\": "
67  "\"shaders/flutter_gpu_unlit.vert\"}}";
68  std::stringstream error;
69  auto result = ParseShaderBundleConfig(bundle, error);
70  ASSERT_FALSE(result.has_value());
71  ASSERT_STREQ(error.str().c_str(),
72  "Invalid shader entry \"UnlitVertex\": Shader type "
73  "\"invalid\" is unknown.\n");
74 }
75 
76 TEST(ShaderBundleTest, ParseShaderBundleConfigFailsForInvalidLanguage) {
77  std::string bundle =
78  "{\"UnlitVertex\": {\"type\": \"vertex\", \"language\": \"invalid\", "
79  "\"file\": \"shaders/flutter_gpu_unlit.vert\"}}";
80  std::stringstream error;
81  auto result = ParseShaderBundleConfig(bundle, error);
82  ASSERT_FALSE(result.has_value());
83  ASSERT_STREQ(error.str().c_str(),
84  "Invalid shader entry \"UnlitVertex\": Unknown language type "
85  "\"invalid\".\n");
86 }
87 
88 TEST(ShaderBundleTest, ParseShaderBundleConfigReturnsExpectedConfig) {
89  std::string bundle =
91  std::stringstream error;
92  auto result = ParseShaderBundleConfig(bundle, error);
93  ASSERT_TRUE(result.has_value());
94  ASSERT_STREQ(error.str().c_str(), "");
95 
96  // NOLINTBEGIN(bugprone-unchecked-optional-access)
97  auto maybe_vertex = result->find("UnlitVertex");
98  auto maybe_fragment = result->find("UnlitFragment");
99  ASSERT_TRUE(maybe_vertex != result->end());
100  ASSERT_TRUE(maybe_fragment != result->end());
101  auto vertex = maybe_vertex->second;
102  auto fragment = maybe_fragment->second;
103  // NOLINTEND(bugprone-unchecked-optional-access)
104 
105  EXPECT_EQ(vertex.type, SourceType::kVertexShader);
106  EXPECT_EQ(vertex.language, SourceLanguage::kGLSL);
107  EXPECT_STREQ(vertex.entry_point.c_str(), "main");
108  EXPECT_STREQ(vertex.source_file_name.c_str(),
109  "shaders/flutter_gpu_unlit.vert");
110 
111  EXPECT_EQ(fragment.type, SourceType::kFragmentShader);
112  EXPECT_EQ(fragment.language, SourceLanguage::kGLSL);
113  EXPECT_STREQ(fragment.entry_point.c_str(), "main");
114  EXPECT_STREQ(fragment.source_file_name.c_str(),
115  "shaders/flutter_gpu_unlit.frag");
116 }
117 
118 template <typename T>
119 const T* FindByName(const std::vector<std::unique_ptr<T>>& collection,
120  const std::string& name) {
121  const auto maybe = std::find_if(
122  collection.begin(), collection.end(),
123  [&name](const std::unique_ptr<T>& value) { return value->name == name; });
124  if (maybe == collection.end()) {
125  return nullptr;
126  }
127  return maybe->get();
128 }
129 
130 TEST(ShaderBundleTest, GenerateShaderBundleFlatbufferProducesCorrectResult) {
131  std::string fixtures_path = flutter::testing::GetFixturesPath();
132  std::string config =
133  "{\"UnlitFragment\": {\"type\": \"fragment\", \"file\": \"" +
134  fixtures_path +
135  "/flutter_gpu_unlit.frag\"}, \"UnlitVertex\": {\"type\": "
136  "\"vertex\", \"file\": \"" +
137  fixtures_path + "/flutter_gpu_unlit.vert\"}}";
138 
139  SourceOptions options;
142 
143  std::optional<fb::shaderbundle::ShaderBundleT> bundle =
144  GenerateShaderBundleFlatbuffer(config, options);
145  ASSERT_TRUE(bundle.has_value());
146 
147  // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
148  const auto& shaders = bundle->shaders;
149  const auto* vertex = FindByName(shaders, "UnlitVertex");
150  const auto* fragment = FindByName(shaders, "UnlitFragment");
151  ASSERT_NE(vertex, nullptr);
152  ASSERT_NE(fragment, nullptr);
153 
154  // --------------------------------------------------------------------------
155  /// Verify vertex shader.
156  ///
157 
158  EXPECT_STREQ(vertex->metal_desktop->entrypoint.c_str(),
159  "flutter_gpu_unlit_vertex_main");
160  EXPECT_EQ(vertex->metal_desktop->stage,
161  fb::shaderbundle::ShaderStage::kVertex);
162 
163  // Inputs.
164  ASSERT_EQ(vertex->metal_desktop->inputs.size(), 1u);
165  const auto& v_in_position = vertex->metal_desktop->inputs[0];
166  EXPECT_STREQ(v_in_position->name.c_str(), "position");
167  EXPECT_EQ(v_in_position->location, 0u);
168  EXPECT_EQ(v_in_position->set, 0u);
169  EXPECT_EQ(v_in_position->binding, 0u);
170  EXPECT_EQ(v_in_position->type, fb::shaderbundle::InputDataType::kFloat);
171  EXPECT_EQ(v_in_position->bit_width, 32u);
172  EXPECT_EQ(v_in_position->vec_size, 2u);
173  EXPECT_EQ(v_in_position->columns, 1u);
174  EXPECT_EQ(v_in_position->offset, 0u);
175 
176  // Uniforms.
177  ASSERT_EQ(vertex->metal_desktop->uniform_structs.size(), 1u);
178  const auto* vert_info =
179  FindByName(vertex->metal_desktop->uniform_structs, "VertInfo");
180  ASSERT_NE(vert_info, nullptr);
181  EXPECT_EQ(vert_info->ext_res_0, 0u);
182  EXPECT_EQ(vert_info->set, 0u);
183  EXPECT_EQ(vert_info->binding, 0u);
184  ASSERT_EQ(vert_info->fields.size(), 2u);
185  const auto& mvp = vert_info->fields[0];
186  EXPECT_STREQ(mvp->name.c_str(), "mvp");
187  EXPECT_EQ(mvp->type, fb::shaderbundle::UniformDataType::kFloat);
188  EXPECT_EQ(mvp->offset_in_bytes, 0u);
189  EXPECT_EQ(mvp->element_size_in_bytes, 64u);
190  EXPECT_EQ(mvp->total_size_in_bytes, 64u);
191  EXPECT_EQ(mvp->array_elements, 0u);
192  const auto& color = vert_info->fields[1];
193  EXPECT_STREQ(color->name.c_str(), "color");
194  EXPECT_EQ(color->type, fb::shaderbundle::UniformDataType::kFloat);
195  EXPECT_EQ(color->offset_in_bytes, 64u);
196  EXPECT_EQ(color->element_size_in_bytes, 16u);
197  EXPECT_EQ(color->total_size_in_bytes, 16u);
198  EXPECT_EQ(color->array_elements, 0u);
199 
200  // --------------------------------------------------------------------------
201  /// Verify fragment shader.
202  ///
203 
204  EXPECT_STREQ(fragment->metal_desktop->entrypoint.c_str(),
205  "flutter_gpu_unlit_fragment_main");
206  EXPECT_EQ(fragment->metal_desktop->stage,
207  fb::shaderbundle::ShaderStage::kFragment);
208 
209  // Inputs (not recorded for fragment shaders).
210  ASSERT_EQ(fragment->metal_desktop->inputs.size(), 0u);
211 
212  // Uniforms.
213  ASSERT_EQ(fragment->metal_desktop->inputs.size(), 0u);
214 }
215 
216 } // namespace testing
217 } // namespace compiler
218 } // namespace impeller
int32_t value
const std::string kUnlitFragmentBundleConfig
const T * FindByName(const std::vector< std::unique_ptr< T >> &collection, const std::string &name)
TEST(CompilerTest, Defines)
std::optional< fb::shaderbundle::ShaderBundleT > GenerateShaderBundleFlatbuffer(const std::string &bundle_config_json, const SourceOptions &options)
Parses the JSON shader bundle configuration and invokes the compiler multiple times to produce a shad...
std::optional< ShaderBundleConfig > ParseShaderBundleConfig(const std::string &bundle_config_json, std::ostream &error_stream)
Parse a shader bundle configuration from a given JSON string.