| 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"
10 #include "impeller/base/allocation.h"
11 #include "impeller/base/validation.h"
12 #include "impeller/core/shader_types.h"
13 #include "impeller/playground/playground.h"
14 #include "impeller/renderer/pipeline_descriptor.h"
15 #include "impeller/renderer/pipeline_library.h"
16 #include "impeller/renderer/shader_library.h"
17 #include "impeller/runtime_stage/runtime_stage.h"
18 #include "impeller/runtime_stage/runtime_stage_playground.h"
19
20 namespace impeller {
21 namespace testing {
22
23 using RuntimeStageTest = RuntimeStagePlayground;
24 INSTANTIATE_PLAYGROUND_SUITE(RuntimeStageTest);
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());
33 ASSERT_EQ(stage.GetShaderStage(), RuntimeShaderStage::kFragment);
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));
246 ColorAttachmentDescriptor color0;
247 color0.format = GetContext()->GetCapabilities()->GetDefaultColorFormat();
248 StencilAttachmentDescriptor stencil0;
249 stencil0.stencil_compare = CompareFunction::kEqual;
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:18
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