Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
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 <cstddef>
6#include <future>
7
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
27namespace impeller {
28namespace testing {
29
32
33TEST_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 =
41 stages.value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
42 ASSERT_TRUE(stage);
43 ASSERT_EQ(stage->GetShaderStage(), RuntimeShaderStage::kFragment);
44}
45
46TEST_P(RuntimeStageTest, RejectInvalidFormatVersion) {
47 flatbuffers::FlatBufferBuilder builder;
48 fb::RuntimeStagesBuilder stages_builder(builder);
49 stages_builder.add_format_version(0);
50 auto stages = stages_builder.Finish();
51 builder.Finish(stages, fb::RuntimeStagesIdentifier());
52 auto mapping = std::make_shared<fml::NonOwnedMapping>(
53 builder.GetBufferPointer(), builder.GetSize());
54 auto runtime_stages = RuntimeStage::DecodeRuntimeStages(mapping);
55 EXPECT_FALSE(runtime_stages.ok());
56 EXPECT_EQ(runtime_stages.status().code(), absl::StatusCode::kInvalidArgument);
57}
58
59TEST_P(RuntimeStageTest, CanRejectInvalidBlob) {
60 ScopedValidationDisable disable_validation;
61 const std::shared_ptr<fml::Mapping> fixture =
62 flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
63 ASSERT_TRUE(fixture);
64 auto junk_allocation = std::make_shared<Allocation>();
65 ASSERT_TRUE(junk_allocation->Truncate(Bytes{fixture->GetSize()}, false));
66 // Not meant to be secure. Just reject obviously bad blobs using magic
67 // numbers.
68 ::memset(junk_allocation->GetBuffer(), 127,
69 junk_allocation->GetLength().GetByteSize());
71 CreateMappingFromAllocation(junk_allocation));
72 ASSERT_FALSE(stages.ok());
73}
74
75TEST_P(RuntimeStageTest, CanReadUniforms) {
76 const std::shared_ptr<fml::Mapping> fixture =
78 "all_supported_uniforms.frag.iplr");
79 ASSERT_TRUE(fixture);
80 ASSERT_GT(fixture->GetSize(), 0u);
81 auto stages = RuntimeStage::DecodeRuntimeStages(fixture);
82 ABSL_ASSERT_OK(stages);
83 auto stage =
84 stages.value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
85
86 ASSERT_TRUE(stage);
87 switch (GetBackend()) {
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 EXPECT_EQ(padding.size(), 4u);
123 EXPECT_EQ(padding[0], RuntimePaddingType::kFloat);
124 EXPECT_EQ(padding[1], RuntimePaddingType::kFloat);
125 EXPECT_EQ(padding[2], RuntimePaddingType::kFloat);
127 } else {
128 EXPECT_TRUE(padding.empty());
129 }
130 }
131 {
132 // uVec4
133 auto uni = stage->GetUniform("uVec4");
134 ASSERT_NE(uni, nullptr);
135 EXPECT_EQ(uni->dimensions.rows, 4u);
136 EXPECT_EQ(uni->dimensions.cols, 1u);
137 EXPECT_EQ(uni->location, 3u);
138 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
139 EXPECT_TRUE(uni->padding_layout.empty());
140 }
141 {
142 // uMat2
143 auto uni = stage->GetUniform("uMat2");
144 ASSERT_NE(uni, nullptr);
145 EXPECT_EQ(uni->dimensions.rows, 2u);
146 EXPECT_EQ(uni->dimensions.cols, 2u);
147 EXPECT_EQ(uni->location, 4u);
148 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
149 EXPECT_TRUE(uni->padding_layout.empty());
150 }
151 {
152 // uMat3
153 auto uni = stage->GetUniform("uMat3");
154 ASSERT_NE(uni, nullptr);
155 EXPECT_EQ(uni->dimensions.rows, 3u);
156 EXPECT_EQ(uni->dimensions.cols, 3u);
157 EXPECT_EQ(uni->location, 5u);
158 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
159 }
160 {
161 // uMat4
162 auto uni = stage->GetUniform("uMat4");
163 ASSERT_NE(uni, nullptr);
164 EXPECT_EQ(uni->dimensions.rows, 4u);
165 EXPECT_EQ(uni->dimensions.cols, 4u);
166 EXPECT_EQ(uni->location, 6u);
167 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
168 EXPECT_TRUE(uni->padding_layout.empty());
169 }
170 {
171 // uFloatArray
172 auto uni = stage->GetUniform("uFloatArray");
173 ASSERT_NE(uni, nullptr);
174 EXPECT_EQ(uni->dimensions.rows, 1u);
175 EXPECT_EQ(uni->dimensions.cols, 1u);
176 EXPECT_EQ(uni->location, 7u);
177 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
178 EXPECT_TRUE(uni->padding_layout.empty());
179 }
180 {
181 auto uni = stage->GetUniform("uVec2Array");
182 ASSERT_NE(uni, nullptr);
183 EXPECT_EQ(uni->dimensions.rows, 2u);
184 EXPECT_EQ(uni->dimensions.cols, 1u);
185 EXPECT_EQ(uni->location, 9u);
186 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
187 EXPECT_TRUE(uni->padding_layout.empty());
188 }
189 {
190 // uVec3Array
191 auto uni = stage->GetUniform("uVec3Array");
192 ASSERT_NE(uni, nullptr);
193 EXPECT_EQ(uni->dimensions.rows, 3u);
194 EXPECT_EQ(uni->dimensions.cols, 1u);
195 EXPECT_EQ(uni->location, 11u);
196 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
197 }
198 {
199 // uVec4Array
200 auto uni = stage->GetUniform("uVec4Array");
201 ASSERT_NE(uni, nullptr);
202 EXPECT_EQ(uni->dimensions.rows, 4u);
203 EXPECT_EQ(uni->dimensions.cols, 1u);
204 EXPECT_EQ(uni->location, 13u);
205 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
206 EXPECT_TRUE(uni->padding_layout.empty());
207 }
208 {
209 // uMat2Array
210 auto uni = stage->GetUniform("uMat2Array");
211 ASSERT_NE(uni, nullptr);
212 EXPECT_EQ(uni->dimensions.rows, 2u);
213 EXPECT_EQ(uni->dimensions.cols, 2u);
214 EXPECT_EQ(uni->location, 15u);
215 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
216 EXPECT_TRUE(uni->padding_layout.empty());
217 }
218 {
219 // uMat3Array
220 auto uni = stage->GetUniform("uMat3Array");
221 ASSERT_NE(uni, nullptr);
222 EXPECT_EQ(uni->dimensions.rows, 3u);
223 EXPECT_EQ(uni->dimensions.cols, 3u);
224 EXPECT_EQ(uni->location, 17u);
225 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
226 }
227 {
228 // uMat4Array
229 auto uni = stage->GetUniform("uMat4Array");
230 ASSERT_NE(uni, nullptr);
231 EXPECT_EQ(uni->dimensions.rows, 4u);
232 EXPECT_EQ(uni->dimensions.cols, 4u);
233 EXPECT_EQ(uni->location, 19u);
234 EXPECT_EQ(uni->type, RuntimeUniformType::kFloat);
235 EXPECT_TRUE(uni->padding_layout.empty());
236 }
237 break;
238 }
240 EXPECT_EQ(stage->GetUniforms().size(), 1u);
241 const RuntimeUniformDescription* uni =
242 stage->GetUniform(RuntimeStage::kVulkanUBOName);
243 ASSERT_TRUE(uni);
244 EXPECT_EQ(uni->type, RuntimeUniformType::kStruct);
245 EXPECT_EQ(uni->struct_float_count, 26u);
246
247 EXPECT_EQ(uni->GetGPUSize(), 640u);
248 std::vector<RuntimePaddingType> layout(uni->GetGPUSize() / sizeof(float),
250 // uFloat and uVec2 are packed into a vec4 with 1 byte of padding between.
252 // uVec3 is packed as a vec4 with 1 byte of padding.
254 // uMat2 is packed as two vec4s, with the last 2 bytes of each being
255 // padding.
256 layout[14] = RuntimePaddingType::kPadding;
257 layout[15] = RuntimePaddingType::kPadding;
258 layout[18] = RuntimePaddingType::kPadding;
259 layout[19] = RuntimePaddingType::kPadding;
260 // uMat3 is packed as 3 vec4s, with the last byte of each being padding
261 layout[23] = RuntimePaddingType::kPadding;
262 layout[27] = RuntimePaddingType::kPadding;
263 layout[31] = RuntimePaddingType::kPadding;
264 // uFloatArray is packed as 2 vec4s, with the last 3 bytes of each
265 // being padding.
266 layout[49] = RuntimePaddingType::kPadding;
267 layout[50] = RuntimePaddingType::kPadding;
268 layout[51] = RuntimePaddingType::kPadding;
269 layout[53] = RuntimePaddingType::kPadding;
270 layout[54] = RuntimePaddingType::kPadding;
271 layout[55] = RuntimePaddingType::kPadding;
272 // uVec2Array is packed as 2 vec4s, with 2 bytes of padding at the end of
273 // each.
274 layout[58] = RuntimePaddingType::kPadding;
275 layout[59] = RuntimePaddingType::kPadding;
276 layout[62] = RuntimePaddingType::kPadding;
277 layout[63] = RuntimePaddingType::kPadding;
278 // uVec3Array is packed as 2 vec4s, with the last byte of each as padding.
279 layout[67] = RuntimePaddingType::kPadding;
280 layout[71] = RuntimePaddingType::kPadding;
281 // uVec4Array has no padding.
282 // uMat2Array[2] is packed as 4 vec4s, With the last 2 bytes of each being
283 // padding.
284 layout[82] = RuntimePaddingType::kPadding;
285 layout[83] = RuntimePaddingType::kPadding;
286 layout[86] = RuntimePaddingType::kPadding;
287 layout[87] = RuntimePaddingType::kPadding;
288 layout[90] = RuntimePaddingType::kPadding;
289 layout[91] = RuntimePaddingType::kPadding;
290 layout[94] = RuntimePaddingType::kPadding;
291 layout[95] = RuntimePaddingType::kPadding;
292 // uMat3Array[2] is packed as 6 vec4s, with the last byte of each being
293 // padding.
294 layout[99] = RuntimePaddingType::kPadding;
295 layout[103] = RuntimePaddingType::kPadding;
296 layout[107] = RuntimePaddingType::kPadding;
297 layout[111] = RuntimePaddingType::kPadding;
298 layout[115] = RuntimePaddingType::kPadding;
299 layout[119] = RuntimePaddingType::kPadding;
300 // uMat4Array[2] is packed as 8 vec4s with no padding.
301 layout[152] = RuntimePaddingType::kPadding;
302 layout[153] = RuntimePaddingType::kPadding;
303 layout[154] = RuntimePaddingType::kPadding;
304 layout[155] = RuntimePaddingType::kPadding;
305 layout[156] = RuntimePaddingType::kPadding;
306 layout[157] = RuntimePaddingType::kPadding;
307 layout[158] = RuntimePaddingType::kPadding;
308 layout[159] = RuntimePaddingType::kPadding;
309
310 EXPECT_THAT(uni->padding_layout, ::testing::ElementsAreArray(layout));
311
312 std::vector<std::pair<std::string, unsigned int>> expected_uniforms = {
313 {"uFloat", 4}, {"uVec2", 8}, {"uVec3", 12},
314 {"uVec4", 16}, {"uMat2", 16}, {"uMat3", 36},
315 {"uMat4", 64}, {"uFloatArray", 8}, {"uVec2Array", 16},
316 {"uVec3Array", 24}, {"uVec4Array", 32}, {"uMat2Array", 32},
317 {"uMat3Array", 72}, {"uMat4Array", 128}};
318
319 ASSERT_EQ(uni->struct_fields.size(), expected_uniforms.size());
320
321 for (size_t i = 0; i < expected_uniforms.size(); ++i) {
322 const auto& element = uni->struct_fields[i];
323 const auto& expected = expected_uniforms[i];
324
325 EXPECT_EQ(element.name, expected.first) << "index: " << i;
326 EXPECT_EQ(element.byte_size, expected.second) << "index: " << i;
327 }
328 break;
329 }
330 }
331}
332
333TEST_P(RuntimeStageTest, CanReadUniformsSamplerBeforeUBO) {
334 if (GetBackend() != PlaygroundBackend::kVulkan) {
335 GTEST_SKIP() << "Test only relevant for Vulkan";
336 }
337 const std::shared_ptr<fml::Mapping> fixture =
339 "uniforms_and_sampler_1.frag.iplr");
340 ASSERT_TRUE(fixture);
341 ASSERT_GT(fixture->GetSize(), 0u);
342 auto stages = RuntimeStage::DecodeRuntimeStages(fixture);
343 ABSL_ASSERT_OK(stages);
344 auto stage =
345 stages.value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
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
360TEST_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 =
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 =
372 stages.value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
373
374 EXPECT_EQ(stage->GetUniforms().size(), 2u);
375 auto uni = stage->GetUniform(RuntimeStage::kVulkanUBOName);
376 ASSERT_TRUE(uni);
377 // Struct must be offset at 45.
378 EXPECT_EQ(uni->type, RuntimeUniformType::kStruct);
379 EXPECT_EQ(uni->binding, 64u);
380 // Sampler should be offset at 64 but due to current bug
381 // has offset of 0, the correct offset is computed at runtime.
382 auto sampler_uniform = stage->GetUniform("u_texture");
383 EXPECT_EQ(sampler_uniform->type, RuntimeUniformType::kSampledImage);
384 EXPECT_EQ(sampler_uniform->binding, 65u);
385}
386
387TEST_P(RuntimeStageTest, CanRegisterStage) {
388 const std::shared_ptr<fml::Mapping> fixture =
389 flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
390 ASSERT_TRUE(fixture);
391 ASSERT_GT(fixture->GetSize(), 0u);
392 auto stages = RuntimeStage::DecodeRuntimeStages(fixture);
393 ABSL_ASSERT_OK(stages);
394 auto stage =
395 stages.value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
396 ASSERT_TRUE(stage);
397 std::promise<bool> registration;
398 auto future = registration.get_future();
399 auto library = GetContext()->GetShaderLibrary();
400 library->RegisterFunction(
401 stage->GetEntrypoint(), //
402 ToShaderStage(stage->GetShaderStage()), //
403 stage->GetCodeMapping(), //
404 fml::MakeCopyable([reg = std::move(registration)](bool result) mutable {
405 reg.set_value(result);
406 }));
407 ASSERT_TRUE(future.get());
408 {
409 auto function =
410 library->GetFunction(stage->GetEntrypoint(), ShaderStage::kFragment);
411 ASSERT_NE(function, nullptr);
412 }
413
414 // Check if unregistering works.
415
416 library->UnregisterFunction(stage->GetEntrypoint(), ShaderStage::kFragment);
417 {
418 auto function =
419 library->GetFunction(stage->GetEntrypoint(), ShaderStage::kFragment);
420 ASSERT_EQ(function, nullptr);
421 }
422}
423
424TEST_P(RuntimeStageTest, CanCreatePipelineFromRuntimeStage) {
425 auto stages_result = OpenAssetAsRuntimeStage("ink_sparkle.frag.iplr");
426 ABSL_ASSERT_OK(stages_result);
427 auto stage =
428 stages_result
429 .value()[PlaygroundBackendToRuntimeStageBackend(GetBackend())];
430
431 ASSERT_TRUE(stage);
432 ASSERT_NE(stage, nullptr);
433 ASSERT_TRUE(RegisterStage(*stage));
434 auto library = GetContext()->GetShaderLibrary();
435 using VS = RuntimeEffectVertexShader;
437 desc.SetLabel("Runtime Stage InkSparkle");
439 library->GetFunction(VS::kEntrypointName, ShaderStage::kVertex));
441 library->GetFunction(stage->GetEntrypoint(), ShaderStage::kFragment));
442 auto vertex_descriptor = std::make_shared<VertexDescriptor>();
443 vertex_descriptor->SetStageInputs(VS::kAllShaderStageInputs,
444 VS::kInterleavedBufferLayout);
445
446 std::array<DescriptorSetLayout, 2> descriptor_set_layouts = {
447 VS::kDescriptorSetLayouts[0],
449 .binding = 64u,
450 .descriptor_type = DescriptorType::kUniformBuffer,
451 .shader_stage = ShaderStage::kFragment,
452 },
453 };
454 vertex_descriptor->RegisterDescriptorSetLayouts(descriptor_set_layouts);
455
456 desc.SetVertexDescriptor(std::move(vertex_descriptor));
458 color0.format = GetContext()->GetCapabilities()->GetDefaultColorFormat();
461 desc.SetColorAttachmentDescriptor(0u, color0);
462 desc.SetStencilAttachmentDescriptors(stencil0);
463 const auto stencil_fmt =
464 GetContext()->GetCapabilities()->GetDefaultStencilFormat();
465 desc.SetStencilPixelFormat(stencil_fmt);
466 auto pipeline = GetContext()->GetPipelineLibrary()->GetPipeline(desc).Get();
467 ASSERT_NE(pipeline, nullptr);
468}
469
470TEST_P(RuntimeStageTest, ContainsExpectedShaderTypes) {
471 auto stages_result = OpenAssetAsRuntimeStage("ink_sparkle.frag.iplr");
472 ABSL_ASSERT_OK(stages_result);
473 auto stages = stages_result.value();
474 // Right now, SkSL gets implicitly bundled regardless of what the build rule
475 // for this test requested. After
476 // https://github.com/flutter/flutter/issues/138919, this may require a build
477 // rule change or a new test.
478 EXPECT_TRUE(stages[RuntimeStageBackend::kSkSL]);
479
480 EXPECT_TRUE(stages[RuntimeStageBackend::kOpenGLES]);
481 EXPECT_TRUE(stages[RuntimeStageBackend::kMetal]);
482 EXPECT_TRUE(stages[RuntimeStageBackend::kVulkan]);
483}
484
485} // namespace testing
486} // 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
static absl::StatusOr< Map > DecodeRuntimeStages(const std::shared_ptr< fml::Mapping > &payload)
Dart_NativeFunction function
Definition fuchsia.cc:50
Vector2 padding
The halo padding in source space.
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:58
internal::CopyableLambda< T > MakeCopyable(T lambda)
TEST_P(AiksTest, DrawAtlasNoColor)
constexpr RuntimeStageBackend PlaygroundBackendToRuntimeStageBackend(PlaygroundBackend backend)
Definition playground.h:33
constexpr ShaderStage ToShaderStage(RuntimeShaderStage stage)
@ 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
#define INSTANTIATE_PLAYGROUND_SUITE(playground)
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
std::vector< RuntimePaddingType > padding_layout