Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
runtime_stage_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 <future>
6
7#include "flutter/fml/make_copyable.h"
8#include "flutter/testing/testing.h"
9#include "gmock/gmock.h"
14#include "impeller/entity/runtime_effect.vert.h"
21
22namespace impeller {
23namespace testing {
24
27
28TEST_P(RuntimeStageTest, CanReadValidBlob) {
29 const std::shared_ptr<fml::Mapping> fixture =
30 flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
31 ASSERT_TRUE(fixture);
32 ASSERT_GT(fixture->GetSize(), 0u);
33 auto stages = RuntimeStage::DecodeRuntimeStages(fixture);
34 auto stage = stages[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
35 ASSERT_TRUE(stage->IsValid());
36 ASSERT_EQ(stage->GetShaderStage(), RuntimeShaderStage::kFragment);
37}
38
39TEST_P(RuntimeStageTest, CanRejectInvalidBlob) {
40 ScopedValidationDisable disable_validation;
41 const std::shared_ptr<fml::Mapping> fixture =
42 flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
43 ASSERT_TRUE(fixture);
44 auto junk_allocation = std::make_shared<Allocation>();
45 ASSERT_TRUE(junk_allocation->Truncate(fixture->GetSize(), false));
46 // Not meant to be secure. Just reject obviously bad blobs using magic
47 // numbers.
48 ::memset(junk_allocation->GetBuffer(), 127, junk_allocation->GetLength());
50 CreateMappingFromAllocation(junk_allocation));
51 ASSERT_FALSE(stages[PlaygroundBackendToRuntimeStageBackend(GetBackend())]);
52}
53
54TEST_P(RuntimeStageTest, CanReadUniforms) {
55 const std::shared_ptr<fml::Mapping> fixture =
56 flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
57 ASSERT_TRUE(fixture);
58 ASSERT_GT(fixture->GetSize(), 0u);
59 auto stages = RuntimeStage::DecodeRuntimeStages(fixture);
60 auto stage = stages[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
61
62 ASSERT_TRUE(stage->IsValid());
63 switch (GetBackend()) {
65 [[fallthrough]];
67 ASSERT_EQ(stage->GetUniforms().size(), 17u);
68 {
69 auto uni = stage->GetUniform("u_color");
70 ASSERT_NE(uni, nullptr);
71 EXPECT_EQ(uni->dimensions.rows, 4u);
72 EXPECT_EQ(uni->dimensions.cols, 1u);
73 EXPECT_EQ(uni->location, 0u);
74 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
75 }
76 {
77 auto uni = stage->GetUniform("u_alpha");
78 ASSERT_NE(uni, nullptr);
79 EXPECT_EQ(uni->dimensions.rows, 1u);
80 EXPECT_EQ(uni->dimensions.cols, 1u);
81 EXPECT_EQ(uni->location, 1u);
82 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
83 }
84 {
85 auto uni = stage->GetUniform("u_sparkle_color");
86 ASSERT_NE(uni, nullptr);
87 EXPECT_EQ(uni->dimensions.rows, 4u);
88 EXPECT_EQ(uni->dimensions.cols, 1u);
89 EXPECT_EQ(uni->location, 2u);
90 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
91 }
92 {
93 auto uni = stage->GetUniform("u_sparkle_alpha");
94 ASSERT_NE(uni, nullptr);
95 EXPECT_EQ(uni->dimensions.rows, 1u);
96 EXPECT_EQ(uni->dimensions.cols, 1u);
97 EXPECT_EQ(uni->location, 3u);
98 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
99 }
100 {
101 auto uni = stage->GetUniform("u_blur");
102 ASSERT_NE(uni, nullptr);
103 EXPECT_EQ(uni->dimensions.rows, 1u);
104 EXPECT_EQ(uni->dimensions.cols, 1u);
105 EXPECT_EQ(uni->location, 4u);
106 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
107 }
108 {
109 auto uni = stage->GetUniform("u_radius_scale");
110 ASSERT_NE(uni, nullptr);
111 EXPECT_EQ(uni->dimensions.rows, 1u);
112 EXPECT_EQ(uni->dimensions.cols, 1u);
113 EXPECT_EQ(uni->location, 6u);
114 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
115 }
116 {
117 auto uni = stage->GetUniform("u_max_radius");
118 ASSERT_NE(uni, nullptr);
119 EXPECT_EQ(uni->dimensions.rows, 1u);
120 EXPECT_EQ(uni->dimensions.cols, 1u);
121 EXPECT_EQ(uni->location, 7u);
122 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
123 }
124 {
125 auto uni = stage->GetUniform("u_resolution_scale");
126 ASSERT_NE(uni, nullptr);
127 EXPECT_EQ(uni->dimensions.rows, 2u);
128 EXPECT_EQ(uni->dimensions.cols, 1u);
129 EXPECT_EQ(uni->location, 8u);
130 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
131 }
132 {
133 auto uni = stage->GetUniform("u_noise_scale");
134 ASSERT_NE(uni, nullptr);
135 EXPECT_EQ(uni->dimensions.rows, 2u);
136 EXPECT_EQ(uni->dimensions.cols, 1u);
137 EXPECT_EQ(uni->location, 9u);
138 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
139 }
140 {
141 auto uni = stage->GetUniform("u_noise_phase");
142 ASSERT_NE(uni, nullptr);
143 EXPECT_EQ(uni->dimensions.rows, 1u);
144 EXPECT_EQ(uni->dimensions.cols, 1u);
145 EXPECT_EQ(uni->location, 10u);
146 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
147 }
148
149 {
150 auto uni = stage->GetUniform("u_circle1");
151 ASSERT_NE(uni, nullptr);
152 EXPECT_EQ(uni->dimensions.rows, 2u);
153 EXPECT_EQ(uni->dimensions.cols, 1u);
154 EXPECT_EQ(uni->location, 11u);
155 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
156 }
157 {
158 auto uni = stage->GetUniform("u_circle2");
159 ASSERT_NE(uni, nullptr);
160 EXPECT_EQ(uni->dimensions.rows, 2u);
161 EXPECT_EQ(uni->dimensions.cols, 1u);
162 EXPECT_EQ(uni->location, 12u);
163 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
164 }
165 {
166 auto uni = stage->GetUniform("u_circle3");
167 ASSERT_NE(uni, nullptr);
168 EXPECT_EQ(uni->dimensions.rows, 2u);
169 EXPECT_EQ(uni->dimensions.cols, 1u);
170 EXPECT_EQ(uni->location, 13u);
171 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
172 }
173 {
174 auto uni = stage->GetUniform("u_rotation1");
175 ASSERT_NE(uni, nullptr);
176 EXPECT_EQ(uni->dimensions.rows, 2u);
177 EXPECT_EQ(uni->dimensions.cols, 1u);
178 EXPECT_EQ(uni->location, 14u);
179 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
180 }
181 {
182 auto uni = stage->GetUniform("u_rotation2");
183 ASSERT_NE(uni, nullptr);
184 EXPECT_EQ(uni->dimensions.rows, 2u);
185 EXPECT_EQ(uni->dimensions.cols, 1u);
186 EXPECT_EQ(uni->location, 15u);
187 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
188 }
189 {
190 auto uni = stage->GetUniform("u_rotation3");
191 ASSERT_NE(uni, nullptr);
192 EXPECT_EQ(uni->dimensions.rows, 2u);
193 EXPECT_EQ(uni->dimensions.cols, 1u);
194 EXPECT_EQ(uni->location, 16u);
195 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
196 }
197 break;
198 }
200 EXPECT_EQ(stage->GetUniforms().size(), 1u);
201 auto uni = stage->GetUniform(RuntimeStage::kVulkanUBOName);
202 ASSERT_TRUE(uni);
203 EXPECT_EQ(uni->type, RuntimeUniformType::kStruct);
204 EXPECT_EQ(uni->struct_float_count, 32u);
205
206 // There are 36 4 byte chunks in the UBO: 32 for the 32 floats, and 4 for
207 // padding. Initialize a vector as if they'll all be floats, then manually
208 // set the few padding bytes. If the shader changes, the padding locations
209 // will change as well. For example, if `u_alpha` was moved to the end,
210 // three bytes of padding could potentially be dropped - or if some of the
211 // scalar floats were changed to vec2 or vec4s, or if any vec3s are
212 // introduced.
213 // This means 36 * 4 = 144 bytes total.
214
215 EXPECT_EQ(uni->GetSize(), 144u);
216 std::vector<uint8_t> layout(uni->GetSize() / sizeof(float), 1);
217 layout[5] = 0;
218 layout[6] = 0;
219 layout[7] = 0;
220 layout[23] = 0;
221
222 EXPECT_THAT(uni->struct_layout, ::testing::ElementsAreArray(layout));
223 break;
224 }
225 }
226}
227
228TEST_P(RuntimeStageTest, CanRegisterStage) {
229 const std::shared_ptr<fml::Mapping> fixture =
230 flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
231 ASSERT_TRUE(fixture);
232 ASSERT_GT(fixture->GetSize(), 0u);
233 auto stages = RuntimeStage::DecodeRuntimeStages(fixture);
234 auto stage = stages[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
235 ASSERT_TRUE(stage->IsValid());
236 std::promise<bool> registration;
237 auto future = registration.get_future();
238 auto library = GetContext()->GetShaderLibrary();
239 library->RegisterFunction(
240 stage->GetEntrypoint(), //
241 ToShaderStage(stage->GetShaderStage()), //
242 stage->GetCodeMapping(), //
243 fml::MakeCopyable([reg = std::move(registration)](bool result) mutable {
244 reg.set_value(result);
245 }));
246 ASSERT_TRUE(future.get());
247 {
248 auto function =
249 library->GetFunction(stage->GetEntrypoint(), ShaderStage::kFragment);
250 ASSERT_NE(function, nullptr);
251 }
252
253 // Check if unregistering works.
254
255 library->UnregisterFunction(stage->GetEntrypoint(), ShaderStage::kFragment);
256 {
257 auto function =
258 library->GetFunction(stage->GetEntrypoint(), ShaderStage::kFragment);
259 ASSERT_EQ(function, nullptr);
260 }
261}
262
263TEST_P(RuntimeStageTest, CanCreatePipelineFromRuntimeStage) {
264 auto stages = OpenAssetAsRuntimeStage("ink_sparkle.frag.iplr");
265 auto stage = stages[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
266
267 ASSERT_TRUE(stage);
268 ASSERT_NE(stage, nullptr);
269 ASSERT_TRUE(RegisterStage(*stage));
270 auto library = GetContext()->GetShaderLibrary();
271 using VS = RuntimeEffectVertexShader;
273 desc.SetLabel("Runtime Stage InkSparkle");
274 desc.AddStageEntrypoint(
275 library->GetFunction(VS::kEntrypointName, ShaderStage::kVertex));
276 desc.AddStageEntrypoint(
277 library->GetFunction(stage->GetEntrypoint(), ShaderStage::kFragment));
278 auto vertex_descriptor = std::make_shared<VertexDescriptor>();
279 vertex_descriptor->SetStageInputs(VS::kAllShaderStageInputs,
280 VS::kInterleavedBufferLayout);
281
282 std::array<DescriptorSetLayout, 2> descriptor_set_layouts = {
283 VS::kDescriptorSetLayouts[0],
285 .binding = 64u,
286 .descriptor_type = DescriptorType::kUniformBuffer,
287 .shader_stage = ShaderStage::kFragment,
288 },
289 };
290 vertex_descriptor->RegisterDescriptorSetLayouts(descriptor_set_layouts);
291
292 desc.SetVertexDescriptor(std::move(vertex_descriptor));
294 color0.format = GetContext()->GetCapabilities()->GetDefaultColorFormat();
297 desc.SetColorAttachmentDescriptor(0u, color0);
298 desc.SetStencilAttachmentDescriptors(stencil0);
299 const auto stencil_fmt =
300 GetContext()->GetCapabilities()->GetDefaultStencilFormat();
301 desc.SetStencilPixelFormat(stencil_fmt);
302 auto pipeline = GetContext()->GetPipelineLibrary()->GetPipeline(desc).Get();
303 ASSERT_NE(pipeline, nullptr);
304}
305
306TEST_P(RuntimeStageTest, ContainsExpectedShaderTypes) {
307 auto stages = OpenAssetAsRuntimeStage("ink_sparkle.frag.iplr");
308 // Right now, SkSL gets implicitly bundled regardless of what the build rule
309 // for this test requested. After
310 // https://github.com/flutter/flutter/issues/138919, this may require a build
311 // rule change or a new test.
313
317}
318
319} // namespace testing
320} // namespace impeller
static const char * kVulkanUBOName
static Map DecodeRuntimeStages(const std::shared_ptr< fml::Mapping > &payload)
GAsyncResult * result
Dart_NativeFunction function
Definition fuchsia.cc:51
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:59
internal::CopyableLambda< T > MakeCopyable(T lambda)
TEST_P(AiksTest, CanRenderAdvancedBlendColorFilterWithSaveLayer)
constexpr RuntimeStageBackend PlaygroundBackendToRuntimeStageBackend(PlaygroundBackend backend)
Definition playground.h:35
constexpr ShaderStage ToShaderStage(RuntimeShaderStage stage)
SolidFillVertexShader VS
@ kEqual
Comparison test passes if new_value == current_value.
std::shared_ptr< fml::Mapping > CreateMappingFromAllocation(const std::shared_ptr< Allocation > &allocation)
Definition allocation.cc:99
#define INSTANTIATE_PLAYGROUND_SUITE(playground)
Describe the color attachment that will be used with this pipeline.
Definition formats.h:500
#define EXPECT_TRUE(handle)
Definition unit_test.h:685