| 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/runtime_stage/runtime_stage_types_flatbuffers.h"
12 #include "impeller/shader_bundle/shader_bundle_flatbuffers.h"
13
14 namespace impeller {
15 namespace compiler {
16 namespace testing {
17
18 const std::string kUnlitFragmentBundleConfig =
19 "\"UnlitFragment\": {\"type\": \"fragment\", \"file\": "
20 "\"shaders/flutter_gpu_unlit.frag\"}";
21 const std::string kUnlitVertexBundleConfig =
22 "\"UnlitVertex\": {\"type\": \"vertex\", \"file\": "
23 "\"shaders/flutter_gpu_unlit.vert\"}";
24
25 TEST(ShaderBundleTest, ParseShaderBundleConfigFailsForInvalidJSON) {
26 std::string bundle = "";
27 std::stringstream error;
28 auto result = ParseShaderBundleConfig(bundle, error);
29 ASSERT_FALSE(result.has_value());
30 ASSERT_STREQ(error.str().c_str(),
31 "The shader bundle is not a valid JSON object.\n");
32 }
33
34 TEST(ShaderBundleTest, ParseShaderBundleConfigFailsWhenEntryNotObject) {
35 std::string bundle = "{\"UnlitVertex\": []}";
36 std::stringstream error;
37 auto result = ParseShaderBundleConfig(bundle, error);
38 ASSERT_FALSE(result.has_value());
39 ASSERT_STREQ(
40 error.str().c_str(),
41 "Invalid shader entry \"UnlitVertex\": Entry is not a JSON object.\n");
42 }
43
44 TEST(ShaderBundleTest, ParseShaderBundleConfigFailsWhenMissingFile) {
45 std::string bundle = "{\"UnlitVertex\": {\"type\": \"vertex\"}}";
46 std::stringstream error;
47 auto result = ParseShaderBundleConfig(bundle, error);
48 ASSERT_FALSE(result.has_value());
49 ASSERT_STREQ(error.str().c_str(),
50 "Invalid shader entry \"UnlitVertex\": Missing required "
51 "\"file\" field.\n");
52 }
53
54 TEST(ShaderBundleTest, ParseShaderBundleConfigFailsWhenMissingType) {
55 std::string bundle =
56 "{\"UnlitVertex\": {\"file\": \"shaders/flutter_gpu_unlit.vert\"}}";
57 std::stringstream error;
58 auto result = ParseShaderBundleConfig(bundle, error);
59 ASSERT_FALSE(result.has_value());
60 ASSERT_STREQ(error.str().c_str(),
61 "Invalid shader entry \"UnlitVertex\": Missing required "
62 "\"type\" field.\n");
63 }
64
65 TEST(ShaderBundleTest, ParseShaderBundleConfigFailsForInvalidType) {
66 std::string bundle =
67 "{\"UnlitVertex\": {\"type\": \"invalid\", \"file\": "
68 "\"shaders/flutter_gpu_unlit.vert\"}}";
69 std::stringstream error;
70 auto result = ParseShaderBundleConfig(bundle, error);
71 ASSERT_FALSE(result.has_value());
72 ASSERT_STREQ(error.str().c_str(),
73 "Invalid shader entry \"UnlitVertex\": Shader type "
74 "\"invalid\" is unknown.\n");
75 }
76
77 TEST(ShaderBundleTest, ParseShaderBundleConfigFailsForInvalidLanguage) {
78 std::string bundle =
79 "{\"UnlitVertex\": {\"type\": \"vertex\", \"language\": \"invalid\", "
80 "\"file\": \"shaders/flutter_gpu_unlit.vert\"}}";
81 std::stringstream error;
82 auto result = ParseShaderBundleConfig(bundle, error);
83 ASSERT_FALSE(result.has_value());
84 ASSERT_STREQ(error.str().c_str(),
85 "Invalid shader entry \"UnlitVertex\": Unknown language type "
86 "\"invalid\".\n");
87 }
88
89 TEST(ShaderBundleTest, ParseShaderBundleConfigReturnsExpectedConfig) {
90 std::string bundle =
91 "{" + kUnlitVertexBundleConfig + ", " + kUnlitFragmentBundleConfig + "}";
92 std::stringstream error;
93 auto result = ParseShaderBundleConfig(bundle, error);
94 ASSERT_TRUE(result.has_value());
95 ASSERT_STREQ(error.str().c_str(), "");
96
97 // NOLINTBEGIN(bugprone-unchecked-optional-access)
98 auto maybe_vertex = result->find("UnlitVertex");
99 auto maybe_fragment = result->find("UnlitFragment");
100 ASSERT_TRUE(maybe_vertex != result->end());
101 ASSERT_TRUE(maybe_fragment != result->end());
102 auto vertex = maybe_vertex->second;
103 auto fragment = maybe_fragment->second;
104 // NOLINTEND(bugprone-unchecked-optional-access)
105
106 EXPECT_EQ(vertex.type, SourceType::kVertexShader);
107 EXPECT_EQ(vertex.language, SourceLanguage::kGLSL);
108 EXPECT_STREQ(vertex.entry_point.c_str(), "main");
109 EXPECT_STREQ(vertex.source_file_name.c_str(),
110 "shaders/flutter_gpu_unlit.vert");
111
112 EXPECT_EQ(fragment.type, SourceType::kFragmentShader);
113 EXPECT_EQ(fragment.language, SourceLanguage::kGLSL);
114 EXPECT_STREQ(fragment.entry_point.c_str(), "main");
115 EXPECT_STREQ(fragment.source_file_name.c_str(),
116 "shaders/flutter_gpu_unlit.frag");
117 }
118
119 template <typename T>
120 const T* FindByName(const std::vector<std::unique_ptr<T>>& collection,
121 const std::string& name) {
122 const auto maybe = std::find_if(
123 collection.begin(), collection.end(),
124 [&name](const std::unique_ptr<T>& value) { return value->name == name; });
125 if (maybe == collection.end()) {
126 return nullptr;
127 }
128 return maybe->get();
129 }
130
131 TEST(ShaderBundleTest, GenerateShaderBundleFlatbufferProducesCorrectResult) {
132 std::string fixtures_path = flutter::testing::GetFixturesPath();
133 std::string config =
134 "{\"UnlitFragment\": {\"type\": \"fragment\", \"file\": \"" +
135 fixtures_path +
136 "/flutter_gpu_unlit.frag\"}, \"UnlitVertex\": {\"type\": "
137 "\"vertex\", \"file\": \"" +
138 fixtures_path + "/flutter_gpu_unlit.vert\"}}";
139
140 SourceOptions options;
141 options.target_platform = TargetPlatform::kRuntimeStageMetal;
142 options.source_language = SourceLanguage::kGLSL;
143
144 std::optional<fb::ShaderBundleT> bundle =
145 GenerateShaderBundleFlatbuffer(config, options);
146 ASSERT_TRUE(bundle.has_value());
147
148 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
149 const auto& shaders = bundle->shaders;
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_TRUE(vertex->shader->metal);
160 EXPECT_STREQ(vertex->shader->metal->entrypoint.c_str(),
161 "flutter_gpu_unlit_vertex_main");
162 EXPECT_EQ(vertex->shader->metal->stage, fb::Stage::kVertex);
163
164 // Inputs.
165 ASSERT_EQ(vertex->shader->metal->inputs.size(), 1u);
166 const auto& v_in_position = vertex->shader->metal->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::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->shader->metal->uniforms.size(), 2u);
179 const auto* v_mvp = FindByName(vertex->shader->metal->uniforms, "mvp");
180 ASSERT_NE(v_mvp, nullptr);
181 EXPECT_EQ(v_mvp->location, 0u);
182 EXPECT_EQ(v_mvp->type, fb::UniformDataType::kFloat);
183 EXPECT_EQ(v_mvp->bit_width, 32u);
184 EXPECT_EQ(v_mvp->rows, 4u);
185 EXPECT_EQ(v_mvp->columns, 4u);
186 EXPECT_EQ(v_mvp->array_elements, 0u);
187 const auto* v_color = FindByName(vertex->shader->metal->uniforms, "color");
188 ASSERT_NE(v_color, nullptr);
189 EXPECT_EQ(v_color->location, 1u);
190 EXPECT_EQ(v_color->type, fb::UniformDataType::kFloat);
191 EXPECT_EQ(v_color->bit_width, 32u);
192 EXPECT_EQ(v_color->rows, 4u);
193 EXPECT_EQ(v_color->columns, 1u);
194 EXPECT_EQ(v_color->array_elements, 0u);
195
196 // --------------------------------------------------------------------------
197 /// Verify fragment shader.
198 ///
199
200 EXPECT_TRUE(fragment->shader->metal);
201 EXPECT_STREQ(fragment->shader->metal->entrypoint.c_str(),
202 "flutter_gpu_unlit_fragment_main");
203 EXPECT_EQ(fragment->shader->metal->stage, fb::Stage::kFragment);
204
205 // Inputs (not recorded for fragment shaders).
206 ASSERT_EQ(fragment->shader->metal->inputs.size(), 0u);
207
208 // Uniforms.
209 ASSERT_EQ(fragment->shader->metal->inputs.size(), 0u);
210 }
211
212 } // namespace testing
213 } // namespace compiler
214 } // namespace impeller
impeller::kFloat
@ kFloat
Definition: runtime_types.h:32
impeller::compiler::testing::TEST
TEST(CompilerTest, ShaderKindMatchingIsSuccessful)
Definition: compiler_unittests.cc:18
shader_bundle.h
impeller::compiler::SourceOptions
Definition: source_options.h:20
impeller::compiler::testing::kUnlitVertexBundleConfig
const std::string kUnlitVertexBundleConfig
Definition: shader_bundle_unittests.cc:21
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::SourceLanguage::kGLSL
@ kGLSL
impeller::compiler::testing::FindByName
const T * FindByName(const std::vector< std::unique_ptr< T >> &collection, const std::string &name)
Definition: shader_bundle_unittests.cc:120
impeller::compiler::SourceOptions::source_language
SourceLanguage source_language
Definition: source_options.h:23
impeller::compiler::SourceType::kFragmentShader
@ kFragmentShader
impeller::compiler::testing::kUnlitFragmentBundleConfig
const std::string kUnlitFragmentBundleConfig
Definition: shader_bundle_unittests.cc:18
source_options.h
impeller::compiler::SourceOptions::target_platform
TargetPlatform target_platform
Definition: source_options.h:22
impeller::compiler::GenerateShaderBundleFlatbuffer
std::optional< fb::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:144
impeller::compiler::TargetPlatform::kRuntimeStageMetal
@ kRuntimeStageMetal
impeller::compiler::SourceType::kVertexShader
@ kVertexShader
impeller
Definition: aiks_context.cc:10
types.h