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 <cstddef>
6 #include <future>
7 
8 #include "flutter/fml/make_copyable.h"
9 #include "flutter/testing/testing.h"
10 #include "gmock/gmock.h"
11 #include "gtest/gtest.h"
16 #include "impeller/entity/runtime_effect.vert.h"
22 #include "impeller/runtime_stage/runtime_stage_flatbuffers.h"
24 #include "runtime_stage_types_flatbuffers.h"
25 #include "third_party/abseil-cpp/absl/status/status_matchers.h"
26 
27 namespace impeller {
28 namespace testing {
29 
32 
33 TEST_P(RuntimeStageTest, CanReadValidBlob) {
34  const std::shared_ptr<fml::Mapping> fixture =
35  flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
36  ASSERT_TRUE(fixture);
37  ASSERT_GT(fixture->GetSize(), 0u);
38  auto stages = RuntimeStage::DecodeRuntimeStages(fixture);
39  ABSL_ASSERT_OK(stages);
40  auto stage = stages.value()[GetRuntimeStageBackend()];
41  ASSERT_TRUE(stage);
42  ASSERT_EQ(stage->GetShaderStage(), RuntimeShaderStage::kFragment);
43 }
44 
45 TEST_P(RuntimeStageTest, RejectInvalidFormatVersion) {
46  flatbuffers::FlatBufferBuilder builder;
47  fb::RuntimeStagesBuilder stages_builder(builder);
48  stages_builder.add_format_version(0);
49  auto stages = stages_builder.Finish();
50  builder.Finish(stages, fb::RuntimeStagesIdentifier());
51  auto mapping = std::make_shared<fml::NonOwnedMapping>(
52  builder.GetBufferPointer(), builder.GetSize());
53  auto runtime_stages = RuntimeStage::DecodeRuntimeStages(mapping);
54  EXPECT_FALSE(runtime_stages.ok());
55  EXPECT_EQ(runtime_stages.status().code(), absl::StatusCode::kInvalidArgument);
56 }
57 
58 TEST_P(RuntimeStageTest, CanRejectInvalidBlob) {
59  ScopedValidationDisable disable_validation;
60  const std::shared_ptr<fml::Mapping> fixture =
61  flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
62  ASSERT_TRUE(fixture);
63  auto junk_allocation = std::make_shared<Allocation>();
64  ASSERT_TRUE(junk_allocation->Truncate(Bytes{fixture->GetSize()}, false));
65  // Not meant to be secure. Just reject obviously bad blobs using magic
66  // numbers.
67  ::memset(junk_allocation->GetBuffer(), 127,
68  junk_allocation->GetLength().GetByteSize());
70  CreateMappingFromAllocation(junk_allocation));
71  ASSERT_FALSE(stages.ok());
72 }
73 
74 TEST_P(RuntimeStageTest, CanReadUniforms) {
75  const std::shared_ptr<fml::Mapping> fixture =
76  flutter::testing::OpenFixtureAsMapping(
77  "all_supported_uniforms.frag.iplr");
78  ASSERT_TRUE(fixture);
79  ASSERT_GT(fixture->GetSize(), 0u);
80  auto stages = RuntimeStage::DecodeRuntimeStages(fixture);
81  ABSL_ASSERT_OK(stages);
82  auto stage = stages.value()[GetRuntimeStageBackend()];
83 
84  ASSERT_TRUE(stage);
85  switch (GetBackend()) {
87  [[fallthrough]];
89  [[fallthrough]];
91  ASSERT_EQ(stage->GetUniforms().size(), 14u);
92  {
93  // uFloat
94  auto uni = stage->GetUniform("uFloat");
95  ASSERT_NE(uni, nullptr);
96  EXPECT_EQ(uni->dimensions.rows, 1u);
97  EXPECT_EQ(uni->dimensions.cols, 1u);
98  EXPECT_EQ(uni->location, 0u);
99  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
100  EXPECT_TRUE(uni->padding_layout.empty());
101  }
102  {
103  // uVec2
104  auto uni = stage->GetUniform("uVec2");
105  ASSERT_NE(uni, nullptr);
106  EXPECT_EQ(uni->dimensions.rows, 2u);
107  EXPECT_EQ(uni->dimensions.cols, 1u);
108  EXPECT_EQ(uni->location, 1u);
109  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
110  EXPECT_TRUE(uni->padding_layout.empty());
111  }
112  {
113  // uVec3
114  auto uni = stage->GetUniform("uVec3");
115  ASSERT_NE(uni, nullptr);
116  EXPECT_EQ(uni->dimensions.rows, 3u);
117  EXPECT_EQ(uni->dimensions.cols, 1u);
118  EXPECT_EQ(uni->location, 2u);
119  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
120  auto padding = uni->padding_layout;
121  if (GetBackend() == PlaygroundBackend::kMetal ||
122  GetBackend() == PlaygroundBackend::kMetalSDF) {
123  EXPECT_EQ(padding.size(), 4u);
124  EXPECT_EQ(padding[0], RuntimePaddingType::kFloat);
125  EXPECT_EQ(padding[1], RuntimePaddingType::kFloat);
126  EXPECT_EQ(padding[2], RuntimePaddingType::kFloat);
127  EXPECT_EQ(padding[3], RuntimePaddingType::kPadding);
128  } else {
129  EXPECT_TRUE(padding.empty());
130  }
131  }
132  {
133  // uVec4
134  auto uni = stage->GetUniform("uVec4");
135  ASSERT_NE(uni, nullptr);
136  EXPECT_EQ(uni->dimensions.rows, 4u);
137  EXPECT_EQ(uni->dimensions.cols, 1u);
138  EXPECT_EQ(uni->location, 3u);
139  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
140  EXPECT_TRUE(uni->padding_layout.empty());
141  }
142  {
143  // uMat2
144  auto uni = stage->GetUniform("uMat2");
145  ASSERT_NE(uni, nullptr);
146  EXPECT_EQ(uni->dimensions.rows, 2u);
147  EXPECT_EQ(uni->dimensions.cols, 2u);
148  EXPECT_EQ(uni->location, 4u);
149  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
150  EXPECT_TRUE(uni->padding_layout.empty());
151  }
152  {
153  // uMat3
154  auto uni = stage->GetUniform("uMat3");
155  ASSERT_NE(uni, nullptr);
156  EXPECT_EQ(uni->dimensions.rows, 3u);
157  EXPECT_EQ(uni->dimensions.cols, 3u);
158  EXPECT_EQ(uni->location, 5u);
159  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
160  }
161  {
162  // uMat4
163  auto uni = stage->GetUniform("uMat4");
164  ASSERT_NE(uni, nullptr);
165  EXPECT_EQ(uni->dimensions.rows, 4u);
166  EXPECT_EQ(uni->dimensions.cols, 4u);
167  EXPECT_EQ(uni->location, 6u);
168  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
169  EXPECT_TRUE(uni->padding_layout.empty());
170  }
171  {
172  // uFloatArray
173  auto uni = stage->GetUniform("uFloatArray");
174  ASSERT_NE(uni, nullptr);
175  EXPECT_EQ(uni->dimensions.rows, 1u);
176  EXPECT_EQ(uni->dimensions.cols, 1u);
177  EXPECT_EQ(uni->location, 7u);
178  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
179  EXPECT_TRUE(uni->padding_layout.empty());
180  }
181  {
182  auto uni = stage->GetUniform("uVec2Array");
183  ASSERT_NE(uni, nullptr);
184  EXPECT_EQ(uni->dimensions.rows, 2u);
185  EXPECT_EQ(uni->dimensions.cols, 1u);
186  EXPECT_EQ(uni->location, 9u);
187  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
188  EXPECT_TRUE(uni->padding_layout.empty());
189  }
190  {
191  // uVec3Array
192  auto uni = stage->GetUniform("uVec3Array");
193  ASSERT_NE(uni, nullptr);
194  EXPECT_EQ(uni->dimensions.rows, 3u);
195  EXPECT_EQ(uni->dimensions.cols, 1u);
196  EXPECT_EQ(uni->location, 11u);
197  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
198  }
199  {
200  // uVec4Array
201  auto uni = stage->GetUniform("uVec4Array");
202  ASSERT_NE(uni, nullptr);
203  EXPECT_EQ(uni->dimensions.rows, 4u);
204  EXPECT_EQ(uni->dimensions.cols, 1u);
205  EXPECT_EQ(uni->location, 13u);
206  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
207  EXPECT_TRUE(uni->padding_layout.empty());
208  }
209  {
210  // uMat2Array
211  auto uni = stage->GetUniform("uMat2Array");
212  ASSERT_NE(uni, nullptr);
213  EXPECT_EQ(uni->dimensions.rows, 2u);
214  EXPECT_EQ(uni->dimensions.cols, 2u);
215  EXPECT_EQ(uni->location, 15u);
216  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
217  EXPECT_TRUE(uni->padding_layout.empty());
218  }
219  {
220  // uMat3Array
221  auto uni = stage->GetUniform("uMat3Array");
222  ASSERT_NE(uni, nullptr);
223  EXPECT_EQ(uni->dimensions.rows, 3u);
224  EXPECT_EQ(uni->dimensions.cols, 3u);
225  EXPECT_EQ(uni->location, 17u);
226  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
227  }
228  {
229  // uMat4Array
230  auto uni = stage->GetUniform("uMat4Array");
231  ASSERT_NE(uni, nullptr);
232  EXPECT_EQ(uni->dimensions.rows, 4u);
233  EXPECT_EQ(uni->dimensions.cols, 4u);
234  EXPECT_EQ(uni->location, 19u);
235  EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
236  EXPECT_TRUE(uni->padding_layout.empty());
237  }
238  break;
239  }
241  EXPECT_EQ(stage->GetUniforms().size(), 1u);
242  const RuntimeUniformDescription* uni =
243  stage->GetUniform(RuntimeStage::kVulkanUBOName);
244  ASSERT_TRUE(uni);
245  EXPECT_EQ(uni->type, RuntimeUniformType::kStruct);
246  EXPECT_EQ(uni->struct_float_count, 26u);
247 
248  EXPECT_EQ(uni->GetGPUSize(), 640u);
249  std::vector<RuntimePaddingType> layout(uni->GetGPUSize() / sizeof(float),
251  // uFloat and uVec2 are packed into a vec4 with 1 byte of padding between.
252  layout[1] = RuntimePaddingType::kPadding;
253  // uVec3 is packed as a vec4 with 1 byte of padding.
254  layout[7] = RuntimePaddingType::kPadding;
255  // uMat2 is packed as two vec4s, with the last 2 bytes of each being
256  // padding.
257  layout[14] = RuntimePaddingType::kPadding;
258  layout[15] = RuntimePaddingType::kPadding;
259  layout[18] = RuntimePaddingType::kPadding;
260  layout[19] = RuntimePaddingType::kPadding;
261  // uMat3 is packed as 3 vec4s, with the last byte of each being padding
262  layout[23] = RuntimePaddingType::kPadding;
263  layout[27] = RuntimePaddingType::kPadding;
264  layout[31] = RuntimePaddingType::kPadding;
265  // uFloatArray is packed as 2 vec4s, with the last 3 bytes of each
266  // being padding.
267  layout[49] = RuntimePaddingType::kPadding;
268  layout[50] = RuntimePaddingType::kPadding;
269  layout[51] = RuntimePaddingType::kPadding;
270  layout[53] = RuntimePaddingType::kPadding;
271  layout[54] = RuntimePaddingType::kPadding;
272  layout[55] = RuntimePaddingType::kPadding;
273  // uVec2Array is packed as 2 vec4s, with 2 bytes of padding at the end of
274  // each.
275  layout[58] = RuntimePaddingType::kPadding;
276  layout[59] = RuntimePaddingType::kPadding;
277  layout[62] = RuntimePaddingType::kPadding;
278  layout[63] = RuntimePaddingType::kPadding;
279  // uVec3Array is packed as 2 vec4s, with the last byte of each as padding.
280  layout[67] = RuntimePaddingType::kPadding;
281  layout[71] = RuntimePaddingType::kPadding;
282  // uVec4Array has no padding.
283  // uMat2Array[2] is packed as 4 vec4s, With the last 2 bytes of each being
284  // padding.
285  layout[82] = RuntimePaddingType::kPadding;
286  layout[83] = RuntimePaddingType::kPadding;
287  layout[86] = RuntimePaddingType::kPadding;
288  layout[87] = RuntimePaddingType::kPadding;
289  layout[90] = RuntimePaddingType::kPadding;
290  layout[91] = RuntimePaddingType::kPadding;
291  layout[94] = RuntimePaddingType::kPadding;
292  layout[95] = RuntimePaddingType::kPadding;
293  // uMat3Array[2] is packed as 6 vec4s, with the last byte of each being
294  // padding.
295  layout[99] = RuntimePaddingType::kPadding;
296  layout[103] = RuntimePaddingType::kPadding;
297  layout[107] = RuntimePaddingType::kPadding;
298  layout[111] = RuntimePaddingType::kPadding;
299  layout[115] = RuntimePaddingType::kPadding;
300  layout[119] = RuntimePaddingType::kPadding;
301  // uMat4Array[2] is packed as 8 vec4s with no padding.
302  layout[152] = RuntimePaddingType::kPadding;
303  layout[153] = RuntimePaddingType::kPadding;
304  layout[154] = RuntimePaddingType::kPadding;
305  layout[155] = RuntimePaddingType::kPadding;
306  layout[156] = RuntimePaddingType::kPadding;
307  layout[157] = RuntimePaddingType::kPadding;
308  layout[158] = RuntimePaddingType::kPadding;
309  layout[159] = RuntimePaddingType::kPadding;
310 
311  EXPECT_THAT(uni->padding_layout, ::testing::ElementsAreArray(layout));
312 
313  std::vector<std::pair<std::string, unsigned int>> expected_uniforms = {
314  {"uFloat", 4}, {"uVec2", 8}, {"uVec3", 12},
315  {"uVec4", 16}, {"uMat2", 16}, {"uMat3", 36},
316  {"uMat4", 64}, {"uFloatArray", 8}, {"uVec2Array", 16},
317  {"uVec3Array", 24}, {"uVec4Array", 32}, {"uMat2Array", 32},
318  {"uMat3Array", 72}, {"uMat4Array", 128}};
319 
320  ASSERT_EQ(uni->struct_fields.size(), expected_uniforms.size());
321 
322  for (size_t i = 0; i < expected_uniforms.size(); ++i) {
323  const auto& element = uni->struct_fields[i];
324  const auto& expected = expected_uniforms[i];
325 
326  EXPECT_EQ(element.name, expected.first) << "index: " << i;
327  EXPECT_EQ(element.byte_size, expected.second) << "index: " << i;
328  }
329  break;
330  }
331  }
332 }
333 
334 TEST_P(RuntimeStageTest, CanReadUniformsSamplerBeforeUBO) {
335  if (GetBackend() != PlaygroundBackend::kVulkan) {
336  GTEST_SKIP() << "Test only relevant for Vulkan";
337  }
338  const std::shared_ptr<fml::Mapping> fixture =
339  flutter::testing::OpenFixtureAsMapping(
340  "uniforms_and_sampler_1.frag.iplr");
341  ASSERT_TRUE(fixture);
342  ASSERT_GT(fixture->GetSize(), 0u);
343  auto stages = RuntimeStage::DecodeRuntimeStages(fixture);
344  ABSL_ASSERT_OK(stages);
345  auto stage = stages.value()[GetRuntimeStageBackend()];
346 
347  EXPECT_EQ(stage->GetUniforms().size(), 2u);
348  auto uni = stage->GetUniform(RuntimeStage::kVulkanUBOName);
349  ASSERT_TRUE(uni);
350  // Struct must be offset at 65.
351  EXPECT_EQ(uni->type, RuntimeUniformType::kStruct);
352  EXPECT_EQ(uni->binding, 65u);
353  // Sampler should be offset at 64 but due to current bug
354  // has offset of 0, the correct offset is computed at runtime.
355  auto sampler_uniform = stage->GetUniform("u_texture");
356  EXPECT_EQ(sampler_uniform->type, RuntimeUniformType::kSampledImage);
357  EXPECT_EQ(sampler_uniform->binding, 64u);
358 }
359 
360 TEST_P(RuntimeStageTest, CanReadUniformsSamplerAfterUBO) {
361  if (GetBackend() != PlaygroundBackend::kVulkan) {
362  GTEST_SKIP() << "Test only relevant for Vulkan";
363  }
364  const std::shared_ptr<fml::Mapping> fixture =
365  flutter::testing::OpenFixtureAsMapping(
366  "uniforms_and_sampler_2.frag.iplr");
367  ASSERT_TRUE(fixture);
368  ASSERT_GT(fixture->GetSize(), 0u);
369  auto stages = RuntimeStage::DecodeRuntimeStages(fixture);
370  ABSL_ASSERT_OK(stages);
371  auto stage = stages.value()[GetRuntimeStageBackend()];
372 
373  EXPECT_EQ(stage->GetUniforms().size(), 2u);
374  auto uni = stage->GetUniform(RuntimeStage::kVulkanUBOName);
375  ASSERT_TRUE(uni);
376  // Struct must be offset at 45.
377  EXPECT_EQ(uni->type, RuntimeUniformType::kStruct);
378  EXPECT_EQ(uni->binding, 64u);
379  // Sampler should be offset at 64 but due to current bug
380  // has offset of 0, the correct offset is computed at runtime.
381  auto sampler_uniform = stage->GetUniform("u_texture");
382  EXPECT_EQ(sampler_uniform->type, RuntimeUniformType::kSampledImage);
383  EXPECT_EQ(sampler_uniform->binding, 65u);
384 }
385 
386 TEST_P(RuntimeStageTest, CanRegisterStage) {
387  const std::shared_ptr<fml::Mapping> fixture =
388  flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
389  ASSERT_TRUE(fixture);
390  ASSERT_GT(fixture->GetSize(), 0u);
391  auto stages = RuntimeStage::DecodeRuntimeStages(fixture);
392  ABSL_ASSERT_OK(stages);
393  auto stage = stages.value()[GetRuntimeStageBackend()];
394  ASSERT_TRUE(stage);
395  std::promise<bool> registration;
396  auto future = registration.get_future();
397  auto library = GetContext()->GetShaderLibrary();
398  library->RegisterFunction(
399  stage->GetEntrypoint(), //
400  ToShaderStage(stage->GetShaderStage()), //
401  stage->GetCodeMapping(), //
402  fml::MakeCopyable([reg = std::move(registration)](bool result) mutable {
403  reg.set_value(result);
404  }));
405  ASSERT_TRUE(future.get());
406  {
407  auto function =
408  library->GetFunction(stage->GetEntrypoint(), ShaderStage::kFragment);
409  ASSERT_NE(function, nullptr);
410  }
411 
412  // Check if unregistering works.
413 
414  library->UnregisterFunction(stage->GetEntrypoint(), ShaderStage::kFragment);
415  {
416  auto function =
417  library->GetFunction(stage->GetEntrypoint(), ShaderStage::kFragment);
418  ASSERT_EQ(function, nullptr);
419  }
420 }
421 
422 TEST_P(RuntimeStageTest, CanCreatePipelineFromRuntimeStage) {
423  auto stages_result = OpenAssetAsRuntimeStage("ink_sparkle.frag.iplr");
424  ABSL_ASSERT_OK(stages_result);
425  auto stage = stages_result.value()[GetRuntimeStageBackend()];
426 
427  ASSERT_TRUE(stage);
428  ASSERT_NE(stage, nullptr);
429  ASSERT_TRUE(RegisterStage(*stage));
430  auto library = GetContext()->GetShaderLibrary();
431  using VS = RuntimeEffectVertexShader;
432  PipelineDescriptor desc;
433  desc.SetLabel("Runtime Stage InkSparkle");
434  desc.AddStageEntrypoint(
435  library->GetFunction(VS::kEntrypointName, ShaderStage::kVertex));
436  desc.AddStageEntrypoint(
437  library->GetFunction(stage->GetEntrypoint(), ShaderStage::kFragment));
438  auto vertex_descriptor = std::make_shared<VertexDescriptor>();
439  vertex_descriptor->SetStageInputs(VS::kAllShaderStageInputs,
440  VS::kInterleavedBufferLayout);
441 
442  std::array<DescriptorSetLayout, 2> descriptor_set_layouts = {
443  VS::kDescriptorSetLayouts[0],
445  .binding = 64u,
446  .descriptor_type = DescriptorType::kUniformBuffer,
447  .shader_stage = ShaderStage::kFragment,
448  },
449  };
450  vertex_descriptor->RegisterDescriptorSetLayouts(descriptor_set_layouts);
451 
452  desc.SetVertexDescriptor(std::move(vertex_descriptor));
454  color0.format = GetContext()->GetCapabilities()->GetDefaultColorFormat();
457  desc.SetColorAttachmentDescriptor(0u, color0);
458  desc.SetStencilAttachmentDescriptors(stencil0);
459  const auto stencil_fmt =
460  GetContext()->GetCapabilities()->GetDefaultStencilFormat();
461  desc.SetStencilPixelFormat(stencil_fmt);
462  auto pipeline = GetContext()->GetPipelineLibrary()->GetPipeline(desc).Get();
463  ASSERT_NE(pipeline, nullptr);
464 }
465 
466 TEST_P(RuntimeStageTest, ContainsExpectedShaderTypes) {
467  auto stages_result = OpenAssetAsRuntimeStage("ink_sparkle.frag.iplr");
468  ABSL_ASSERT_OK(stages_result);
469  auto stages = stages_result.value();
470  EXPECT_TRUE(stages[RuntimeStageBackend::kSkSL]);
471  EXPECT_TRUE(stages[RuntimeStageBackend::kOpenGLES]);
472  EXPECT_TRUE(stages[RuntimeStageBackend::kMetal]);
473  EXPECT_TRUE(stages[RuntimeStageBackend::kVulkan]);
474 }
475 
476 TEST_P(RuntimeStageTest, ContainsExpectedShaderTypesNoSksl) {
477  auto stages_result =
478  OpenAssetAsRuntimeStage("runtime_stage_simple_no_sksl.frag.iplr");
479  ABSL_ASSERT_OK(stages_result);
480  auto stages = stages_result.value();
481  EXPECT_FALSE(stages[RuntimeStageBackend::kSkSL]);
482  EXPECT_TRUE(stages[RuntimeStageBackend::kOpenGLES]);
483  EXPECT_TRUE(stages[RuntimeStageBackend::kMetal]);
484  EXPECT_TRUE(stages[RuntimeStageBackend::kVulkan]);
485 }
486 
487 } // namespace testing
488 } // namespace impeller
PipelineDescriptor & SetStencilPixelFormat(PixelFormat format)
PipelineDescriptor & SetVertexDescriptor(std::shared_ptr< VertexDescriptor > vertex_descriptor)
PipelineDescriptor & AddStageEntrypoint(std::shared_ptr< const ShaderFunction > function)
PipelineDescriptor & SetLabel(std::string_view label)
PipelineDescriptor & SetStencilAttachmentDescriptors(std::optional< StencilAttachmentDescriptor > front_and_back)
PipelineDescriptor & SetColorAttachmentDescriptor(size_t index, ColorAttachmentDescriptor desc)
static const char * kVulkanUBOName
Definition: runtime_stage.h:23
static absl::StatusOr< Map > DecodeRuntimeStages(const std::shared_ptr< fml::Mapping > &payload)
Vector2 padding
The halo padding in source space.
static std::optional< RuntimeStageBackend > GetRuntimeStageBackend(TargetPlatform target_platform)
Definition: reflector.cc:317
TEST_P(AiksTest, DrawAtlasNoColor)
INSTANTIATE_PLAYGROUND_SUITE(AiksTest)
constexpr ShaderStage ToShaderStage(RuntimeShaderStage stage)
Definition: shader_types.h:29
@ kEqual
Comparison test passes if new_value == current_value.
std::shared_ptr< fml::Mapping > CreateMappingFromAllocation(const std::shared_ptr< Allocation > &allocation)
Creates a mapping from allocation.
Definition: allocation.cc:99
LinePipeline::VertexShader VS
Describe the color attachment that will be used with this pipeline.
Definition: formats.h:522
size_t GetGPUSize() const
Computes the total number of bytes that this uniform requires for representation in the GPU.
std::vector< StructField > struct_fields
Definition: runtime_types.h:64
std::vector< RuntimePaddingType > padding_layout
Definition: runtime_types.h:61