Flutter Impeller
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/impeller/fixtures/simple.vert.h"
9 #include "flutter/testing/testing.h"
19 
20 namespace impeller {
21 namespace testing {
22 
25 
26 TEST(RuntimeStageTest, CanReadValidBlob) {
27  auto fixture =
28  flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
29  ASSERT_TRUE(fixture);
30  ASSERT_GT(fixture->GetSize(), 0u);
31  RuntimeStage stage(std::move(fixture));
32  ASSERT_TRUE(stage.IsValid());
34 }
35 
36 TEST(RuntimeStageTest, CanRejectInvalidBlob) {
37  ScopedValidationDisable disable_validation;
38  auto fixture =
39  flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
40  ASSERT_TRUE(fixture);
41  auto junk_allocation = std::make_shared<Allocation>();
42  ASSERT_TRUE(junk_allocation->Truncate(fixture->GetSize(), false));
43  // Not meant to be secure. Just reject obviously bad blobs using magic
44  // numbers.
45  ::memset(junk_allocation->GetBuffer(), 127, junk_allocation->GetLength());
46  RuntimeStage stage(CreateMappingFromAllocation(junk_allocation));
47  ASSERT_FALSE(stage.IsValid());
48 }
49 
50 TEST(RuntimeStageTest, CanReadUniforms) {
51  auto fixture =
52  flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
53  ASSERT_TRUE(fixture);
54  ASSERT_GT(fixture->GetSize(), 0u);
55  RuntimeStage stage(std::move(fixture));
56  ASSERT_TRUE(stage.IsValid());
57  ASSERT_EQ(stage.GetUniforms().size(), 17u);
58  {
59  auto uni = stage.GetUniform("u_color");
60  ASSERT_NE(uni, nullptr);
61  ASSERT_EQ(uni->dimensions.rows, 4u);
62  ASSERT_EQ(uni->dimensions.cols, 1u);
63  ASSERT_EQ(uni->location, 0u);
64  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
65  }
66  {
67  auto uni = stage.GetUniform("u_alpha");
68  ASSERT_NE(uni, nullptr);
69  ASSERT_EQ(uni->dimensions.rows, 1u);
70  ASSERT_EQ(uni->dimensions.cols, 1u);
71  ASSERT_EQ(uni->location, 1u);
72  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
73  }
74  {
75  auto uni = stage.GetUniform("u_sparkle_color");
76  ASSERT_NE(uni, nullptr);
77  ASSERT_EQ(uni->dimensions.rows, 4u);
78  ASSERT_EQ(uni->dimensions.cols, 1u);
79  ASSERT_EQ(uni->location, 2u);
80  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
81  }
82  {
83  auto uni = stage.GetUniform("u_sparkle_alpha");
84  ASSERT_NE(uni, nullptr);
85  ASSERT_EQ(uni->dimensions.rows, 1u);
86  ASSERT_EQ(uni->dimensions.cols, 1u);
87  ASSERT_EQ(uni->location, 3u);
88  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
89  }
90  {
91  auto uni = stage.GetUniform("u_blur");
92  ASSERT_NE(uni, nullptr);
93  ASSERT_EQ(uni->dimensions.rows, 1u);
94  ASSERT_EQ(uni->dimensions.cols, 1u);
95  ASSERT_EQ(uni->location, 4u);
96  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
97  }
98  {
99  auto uni = stage.GetUniform("u_radius_scale");
100  ASSERT_NE(uni, nullptr);
101  ASSERT_EQ(uni->dimensions.rows, 1u);
102  ASSERT_EQ(uni->dimensions.cols, 1u);
103  ASSERT_EQ(uni->location, 6u);
104  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
105  }
106  {
107  auto uni = stage.GetUniform("u_max_radius");
108  ASSERT_NE(uni, nullptr);
109  ASSERT_EQ(uni->dimensions.rows, 1u);
110  ASSERT_EQ(uni->dimensions.cols, 1u);
111  ASSERT_EQ(uni->location, 7u);
112  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
113  }
114  {
115  auto uni = stage.GetUniform("u_resolution_scale");
116  ASSERT_NE(uni, nullptr);
117  ASSERT_EQ(uni->dimensions.rows, 2u);
118  ASSERT_EQ(uni->dimensions.cols, 1u);
119  ASSERT_EQ(uni->location, 8u);
120  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
121  }
122  {
123  auto uni = stage.GetUniform("u_noise_scale");
124  ASSERT_NE(uni, nullptr);
125  ASSERT_EQ(uni->dimensions.rows, 2u);
126  ASSERT_EQ(uni->dimensions.cols, 1u);
127  ASSERT_EQ(uni->location, 9u);
128  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
129  }
130  {
131  auto uni = stage.GetUniform("u_noise_phase");
132  ASSERT_NE(uni, nullptr);
133  ASSERT_EQ(uni->dimensions.rows, 1u);
134  ASSERT_EQ(uni->dimensions.cols, 1u);
135  ASSERT_EQ(uni->location, 10u);
136  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
137  }
138 
139  {
140  auto uni = stage.GetUniform("u_circle1");
141  ASSERT_NE(uni, nullptr);
142  ASSERT_EQ(uni->dimensions.rows, 2u);
143  ASSERT_EQ(uni->dimensions.cols, 1u);
144  ASSERT_EQ(uni->location, 11u);
145  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
146  }
147  {
148  auto uni = stage.GetUniform("u_circle2");
149  ASSERT_NE(uni, nullptr);
150  ASSERT_EQ(uni->dimensions.rows, 2u);
151  ASSERT_EQ(uni->dimensions.cols, 1u);
152  ASSERT_EQ(uni->location, 12u);
153  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
154  }
155  {
156  auto uni = stage.GetUniform("u_circle3");
157  ASSERT_NE(uni, nullptr);
158  ASSERT_EQ(uni->dimensions.rows, 2u);
159  ASSERT_EQ(uni->dimensions.cols, 1u);
160  ASSERT_EQ(uni->location, 13u);
161  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
162  }
163  {
164  auto uni = stage.GetUniform("u_rotation1");
165  ASSERT_NE(uni, nullptr);
166  ASSERT_EQ(uni->dimensions.rows, 2u);
167  ASSERT_EQ(uni->dimensions.cols, 1u);
168  ASSERT_EQ(uni->location, 14u);
169  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
170  }
171  {
172  auto uni = stage.GetUniform("u_rotation2");
173  ASSERT_NE(uni, nullptr);
174  ASSERT_EQ(uni->dimensions.rows, 2u);
175  ASSERT_EQ(uni->dimensions.cols, 1u);
176  ASSERT_EQ(uni->location, 15u);
177  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
178  }
179  {
180  auto uni = stage.GetUniform("u_rotation3");
181  ASSERT_NE(uni, nullptr);
182  ASSERT_EQ(uni->dimensions.rows, 2u);
183  ASSERT_EQ(uni->dimensions.cols, 1u);
184  ASSERT_EQ(uni->location, 16u);
185  ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
186  }
187 }
188 
189 TEST_P(RuntimeStageTest, CanRegisterStage) {
190  if (GetParam() != PlaygroundBackend::kMetal) {
191  GTEST_SKIP_("Skipped: https://github.com/flutter/flutter/issues/105538");
192  }
193  auto fixture =
194  flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
195  ASSERT_TRUE(fixture);
196  ASSERT_GT(fixture->GetSize(), 0u);
197  RuntimeStage stage(std::move(fixture));
198  ASSERT_TRUE(stage.IsValid());
199  std::promise<bool> registration;
200  auto future = registration.get_future();
201  auto library = GetContext()->GetShaderLibrary();
202  library->RegisterFunction(
203  stage.GetEntrypoint(), //
204  ToShaderStage(stage.GetShaderStage()), //
205  stage.GetCodeMapping(), //
206  fml::MakeCopyable([reg = std::move(registration)](bool result) mutable {
207  reg.set_value(result);
208  }));
209  ASSERT_TRUE(future.get());
210  {
211  auto function =
212  library->GetFunction(stage.GetEntrypoint(), ShaderStage::kFragment);
213  ASSERT_NE(function, nullptr);
214  }
215 
216  // Check if unregistering works.
217 
218  library->UnregisterFunction(stage.GetEntrypoint(), ShaderStage::kFragment);
219  {
220  auto function =
221  library->GetFunction(stage.GetEntrypoint(), ShaderStage::kFragment);
222  ASSERT_EQ(function, nullptr);
223  }
224 }
225 
226 TEST_P(RuntimeStageTest, CanCreatePipelineFromRuntimeStage) {
227  if (GetParam() != PlaygroundBackend::kMetal) {
228  GTEST_SKIP_("Skipped: https://github.com/flutter/flutter/issues/105538");
229  }
230  auto stage = OpenAssetAsRuntimeStage("ink_sparkle.frag.iplr");
231  ASSERT_NE(stage, nullptr);
232  ASSERT_TRUE(RegisterStage(*stage));
233  auto library = GetContext()->GetShaderLibrary();
234  using VS = SimpleVertexShader;
235  PipelineDescriptor desc;
236  desc.SetLabel("Runtime Stage InkSparkle");
237  desc.AddStageEntrypoint(
238  library->GetFunction(VS::kEntrypointName, ShaderStage::kVertex));
239  desc.AddStageEntrypoint(
240  library->GetFunction(stage->GetEntrypoint(), ShaderStage::kFragment));
241  auto vertex_descriptor = std::make_shared<VertexDescriptor>();
242  vertex_descriptor->SetStageInputs(VS::kAllShaderStageInputs,
243  VS::kInterleavedBufferLayout);
244 
245  desc.SetVertexDescriptor(std::move(vertex_descriptor));
247  color0.format = GetContext()->GetCapabilities()->GetDefaultColorFormat();
250  desc.SetColorAttachmentDescriptor(0u, color0);
251  desc.SetStencilAttachmentDescriptors(stencil0);
252  const auto stencil_fmt =
253  GetContext()->GetCapabilities()->GetDefaultStencilFormat();
254  desc.SetStencilPixelFormat(stencil_fmt);
255  auto pipeline = GetContext()->GetPipelineLibrary()->GetPipeline(desc).Get();
256  ASSERT_NE(pipeline, nullptr);
257 }
258 
259 } // namespace testing
260 } // namespace impeller
impeller::PipelineDescriptor
Definition: pipeline_descriptor.h:30
impeller::kFloat
@ kFloat
Definition: runtime_types.h:24
impeller::RuntimeStage::GetShaderStage
RuntimeShaderStage GetShaderStage() const
Definition: runtime_stage.cc:143
impeller::StencilAttachmentDescriptor::stencil_compare
CompareFunction stencil_compare
Definition: formats.h:550
impeller::PipelineDescriptor::SetStencilAttachmentDescriptors
PipelineDescriptor & SetStencilAttachmentDescriptors(std::optional< StencilAttachmentDescriptor > front_and_back)
Definition: pipeline_descriptor.cc:153
allocation.h
impeller::PipelineDescriptor::SetColorAttachmentDescriptor
PipelineDescriptor & SetColorAttachmentDescriptor(size_t index, ColorAttachmentDescriptor desc)
Definition: pipeline_descriptor.cc:106
impeller::PipelineDescriptor::SetStencilPixelFormat
PipelineDescriptor & SetStencilPixelFormat(PixelFormat format)
Definition: pipeline_descriptor.cc:141
impeller::PlaygroundBackend::kMetal
@ kMetal
shader_library.h
impeller::testing::TEST
TEST(AiksCanvasTest, EmptyCullRect)
Definition: canvas_unittests.cc:17
playground.h
validation.h
impeller::CreateMappingFromAllocation
std::shared_ptr< fml::Mapping > CreateMappingFromAllocation(const std::shared_ptr< Allocation > &allocation)
Definition: allocation.cc:100
impeller::RuntimeStage
Definition: runtime_stage.h:17
impeller::ToShaderStage
constexpr ShaderStage ToShaderStage(RuntimeShaderStage stage)
Definition: shader_types.h:29
impeller::RuntimeStage::GetUniforms
const std::vector< RuntimeUniformDescription > & GetUniforms() const
Definition: runtime_stage.cc:124
impeller::testing::INSTANTIATE_PLAYGROUND_SUITE
INSTANTIATE_PLAYGROUND_SUITE(AiksTest)
impeller::RuntimeStage::GetUniform
const RuntimeUniformDescription * GetUniform(const std::string &name) const
Definition: runtime_stage.cc:129
impeller::testing::TEST_P
TEST_P(AiksTest, RotateColorFilteredPath)
Definition: aiks_unittests.cc:56
impeller::RuntimeShaderStage::kFragment
@ kFragment
runtime_stage.h
impeller::ColorAttachmentDescriptor::format
PixelFormat format
Definition: formats.h:452
impeller::ShaderStage::kFragment
@ kFragment
impeller::RuntimeStagePlayground
Definition: runtime_stage_playground.h:13
pipeline_library.h
impeller::PipelineDescriptor::AddStageEntrypoint
PipelineDescriptor & AddStageEntrypoint(std::shared_ptr< const ShaderFunction > function)
Definition: pipeline_descriptor.cc:77
impeller::ShaderStage::kVertex
@ kVertex
runtime_stage_playground.h
impeller::StencilAttachmentDescriptor
Definition: formats.h:544
impeller::RuntimeStage::IsValid
bool IsValid() const
Definition: runtime_stage.cc:112
impeller::CompareFunction::kEqual
@ kEqual
Comparison test passes if new_value == current_value.
impeller::RuntimeStage::GetEntrypoint
const std::string & GetEntrypoint() const
Definition: runtime_stage.cc:139
pipeline_descriptor.h
impeller::PipelineDescriptor::SetLabel
PipelineDescriptor & SetLabel(std::string label)
Definition: pipeline_descriptor.cc:67
impeller::ScopedValidationDisable
Definition: validation.h:37
shader_types.h
impeller
Definition: aiks_context.cc:10
impeller::RuntimeStage::GetCodeMapping
const std::shared_ptr< fml::Mapping > & GetCodeMapping() const
Definition: runtime_stage.cc:116
impeller::PipelineDescriptor::SetVertexDescriptor
PipelineDescriptor & SetVertexDescriptor(std::shared_ptr< VertexDescriptor > vertex_descriptor)
Definition: pipeline_descriptor.cc:92
impeller::ColorAttachmentDescriptor
Describe the color attachment that will be used with this pipeline.
Definition: formats.h:451