| 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"
6 #include "impeller/compiler/shader_bundle.h"
7
8 #include "flutter/testing/testing.h"
9 #include "impeller/compiler/source_options.h"
10 #include "impeller/compiler/types.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 =
90 "{" + kUnlitVertexBundleConfig + ", " + kUnlitFragmentBundleConfig + "}";
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;
140 options.target_platform = TargetPlatform::kRuntimeStageMetal;
141 options.source_language = SourceLanguage::kGLSL;
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
150 const auto* vertex = FindByName(shaders, "UnlitVertex");
151 const auto* fragment = FindByName(shaders, "UnlitFragment");
152 ASSERT_NE(vertex, nullptr);
153 ASSERT_NE(fragment, nullptr);
154
155 // --------------------------------------------------------------------------
156 /// Verify vertex shader.
157 ///
158
159 EXPECT_STREQ(vertex->metal_desktop->entrypoint.c_str(),
160 "flutter_gpu_unlit_vertex_main");
161 EXPECT_EQ(vertex->metal_desktop->stage,
162 fb::shaderbundle::ShaderStage::kVertex);
163
164 // Inputs.
165 ASSERT_EQ(vertex->metal_desktop->inputs.size(), 1u);
166 const auto& v_in_position = vertex->metal_desktop->inputs[0];
167 EXPECT_STREQ(v_in_position->name.c_str(), "position");
168 EXPECT_EQ(v_in_position->location, 0u);
169 EXPECT_EQ(v_in_position->set, 0u);
170 EXPECT_EQ(v_in_position->binding, 0u);
171 EXPECT_EQ(v_in_position->type, fb::shaderbundle::InputDataType::kFloat);
172 EXPECT_EQ(v_in_position->bit_width, 32u);
173 EXPECT_EQ(v_in_position->vec_size, 2u);
174 EXPECT_EQ(v_in_position->columns, 1u);
175 EXPECT_EQ(v_in_position->offset, 0u);
176
177 // Uniforms.
178 ASSERT_EQ(vertex->metal_desktop->uniform_structs.size(), 1u);
179 const auto* vert_info =
180 FindByName(vertex->metal_desktop->uniform_structs, "VertInfo");
181 ASSERT_NE(vert_info, nullptr);
182 EXPECT_EQ(vert_info->ext_res_0, 0u);
183 EXPECT_EQ(vert_info->set, 0u);
184 EXPECT_EQ(vert_info->binding, 0u);
185 ASSERT_EQ(vert_info->fields.size(), 2u);
186 const auto& mvp = vert_info->fields[0];
187 EXPECT_STREQ(mvp->name.c_str(), "mvp");
188 EXPECT_EQ(mvp->type, fb::shaderbundle::UniformDataType::kFloat);
189 EXPECT_EQ(mvp->offset_in_bytes, 0u);
190 EXPECT_EQ(mvp->element_size_in_bytes, 64u);
191 EXPECT_EQ(mvp->total_size_in_bytes, 64u);
192 EXPECT_EQ(mvp->array_elements, 0u);
193 const auto& color = vert_info->fields[1];
194 EXPECT_STREQ(color->name.c_str(), "color");
195 EXPECT_EQ(color->type, fb::shaderbundle::UniformDataType::kFloat);
196 EXPECT_EQ(color->offset_in_bytes, 64u);
197 EXPECT_EQ(color->element_size_in_bytes, 16u);
198 EXPECT_EQ(color->total_size_in_bytes, 16u);
199 EXPECT_EQ(color->array_elements, 0u);
200
201 // --------------------------------------------------------------------------
202 /// Verify fragment shader.
203 ///
204
205 EXPECT_STREQ(fragment->metal_desktop->entrypoint.c_str(),
206 "flutter_gpu_unlit_fragment_main");
207 EXPECT_EQ(fragment->metal_desktop->stage,
208 fb::shaderbundle::ShaderStage::kFragment);
209
210 // Inputs (not recorded for fragment shaders).
211 ASSERT_EQ(fragment->metal_desktop->inputs.size(), 0u);
212
213 // Uniforms.
214 ASSERT_EQ(fragment->metal_desktop->inputs.size(), 0u);
215 }
216
217 } // namespace testing
218 } // namespace compiler
219 } // namespace impeller
types.h
value
int32_t value
Definition: dl_golden_unittests.cc:459
impeller::compiler::testing::kUnlitFragmentBundleConfig
const std::string kUnlitFragmentBundleConfig
Definition: shader_bundle_unittests.cc:17
impeller::compiler::testing::kUnlitVertexBundleConfig
const std::string kUnlitVertexBundleConfig
Definition: shader_bundle_unittests.cc:20
impeller::compiler::testing::FindByName
const T * FindByName(const std::vector< std::unique_ptr< T >> &collection, const std::string &name)
Definition: shader_bundle_unittests.cc:119
impeller::compiler::testing::TEST
TEST(CompilerTest, Defines)
Definition: compiler_unittests.cc:18
impeller::compiler::SourceType::kFragmentShader
@ kFragmentShader
impeller::compiler::SourceType::kVertexShader
@ kVertexShader
impeller::compiler::GenerateShaderBundleFlatbuffer
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...
Definition: shader_bundle.cc:179
impeller::compiler::SourceLanguage::kGLSL
@ kGLSL
impeller::compiler::ParseShaderBundleConfig
std::optional< ShaderBundleConfig > ParseShaderBundleConfig(const std::string &bundle_config_json, std::ostream &error_stream)
Parse a shader bundle configuration from a given JSON string.
Definition: shader_bundle.cc:19
impeller::compiler::TargetPlatform::kRuntimeStageMetal
@ kRuntimeStageMetal
impeller
Definition: allocation.cc:12
impeller::kFloat
@ kFloat
Definition: runtime_types.h:25
shader_bundle.h
source_options.h
impeller::compiler::SourceOptions
Definition: source_options.h:20
impeller::compiler::SourceOptions::source_language
SourceLanguage source_language
Definition: source_options.h:23
impeller::compiler::SourceOptions::target_platform
TargetPlatform target_platform
Definition: source_options.h:22