Flutter Impeller
runtime_stage.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 
6 
7 #include <array>
8 #include <memory>
9 #include <sstream>
10 
11 #include "fml/mapping.h"
15 #include "impeller/runtime_stage/runtime_stage_flatbuffers.h"
16 #include "runtime_stage_types_flatbuffers.h"
17 
18 namespace impeller {
19 
20 static RuntimeUniformType ToType(fb::UniformDataType type) {
21  switch (type) {
28  }
29  FML_UNREACHABLE();
30 }
31 
32 static RuntimeShaderStage ToShaderStage(fb::Stage stage) {
33  switch (stage) {
34  case fb::Stage::kVertex:
36  case fb::Stage::kFragment:
38  case fb::Stage::kCompute:
40  }
41  FML_UNREACHABLE();
42 }
43 
44 /// The generated name from GLSLang/shaderc for the UBO containing non-opaque
45 /// uniforms specified in the user-written runtime effect shader.
46 ///
47 /// Vulkan does not allow non-opaque uniforms outside of a UBO.
48 const char* RuntimeStage::kVulkanUBOName =
49  "_RESERVED_IDENTIFIER_FIXUP_gl_DefaultUniformBlock";
50 
51 std::unique_ptr<RuntimeStage> RuntimeStage::RuntimeStageIfPresent(
52  const fb::RuntimeStage* runtime_stage,
53  const std::shared_ptr<fml::Mapping>& payload) {
54  if (!runtime_stage) {
55  return nullptr;
56  }
57 
58  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
59  return std::unique_ptr<RuntimeStage>(
60  new RuntimeStage(runtime_stage, payload));
61 }
62 
63 absl::StatusOr<RuntimeStage::Map> RuntimeStage::DecodeRuntimeStages(
64  const std::shared_ptr<fml::Mapping>& payload) {
65  if (payload == nullptr || !payload->GetMapping()) {
66  return absl::InvalidArgumentError("Payload is null or empty.");
67  }
68  if (!fb::RuntimeStagesBufferHasIdentifier(payload->GetMapping())) {
69  return absl::InvalidArgumentError(
70  "Payload does not have valid identifier.");
71  }
72 
73  auto raw_stages = fb::GetRuntimeStages(payload->GetMapping());
74  if (!raw_stages) {
75  return absl::InvalidArgumentError("Failed to get runtime stages.");
76  }
77 
78  const uint32_t version = raw_stages->format_version();
79  const auto expected =
80  static_cast<uint32_t>(fb::RuntimeStagesFormatVersion::kVersion);
81  if (version != expected) {
82  std::stringstream stream;
83  stream << "Unsupported runtime stages format version. Expected " << expected
84  << ", got " << version << ".";
85  return absl::InvalidArgumentError(stream.str());
86  }
87 
88  return Map{
90  RuntimeStageIfPresent(raw_stages->sksl(), payload)},
92  RuntimeStageIfPresent(raw_stages->metal(), payload)},
94  RuntimeStageIfPresent(raw_stages->opengles(), payload)},
96  RuntimeStageIfPresent(raw_stages->opengles3(), payload)},
98  RuntimeStageIfPresent(raw_stages->vulkan(), payload)},
99  };
100 }
101 
102 RuntimeStage::RuntimeStage(const fb::RuntimeStage* runtime_stage,
103  const std::shared_ptr<fml::Mapping>& payload)
104  : payload_(payload) {
105  FML_DCHECK(runtime_stage);
106 
107  stage_ = ToShaderStage(runtime_stage->stage());
108  entrypoint_ = runtime_stage->entrypoint()->str();
109 
110  auto* uniforms = runtime_stage->uniforms();
111 
112  // Note: image bindings are screwy and will always have the same offset.
113  // track the binding of the UBO to determine where the image bindings go.
114  // This is only guaranteed to give us the correct bindings if there is a
115  // single sampler2D.
116  std::optional<size_t> ubo_id;
117  if (uniforms) {
118  for (auto i = uniforms->begin(), end = uniforms->end(); i != end; i++) {
120  desc.name = i->name()->str();
121  desc.location = i->location();
122  desc.binding = i->binding();
123  desc.type = ToType(i->type());
124  if (desc.type == kStruct) {
125  ubo_id = desc.location;
126  desc.binding = desc.location;
127  }
129  static_cast<size_t>(i->rows()), static_cast<size_t>(i->columns())};
130  desc.bit_width = i->bit_width();
131  desc.array_elements = i->array_elements();
132  if (i->struct_layout()) {
133  for (const auto& byte_type : *i->struct_layout()) {
134  desc.struct_layout.push_back(static_cast<uint8_t>(byte_type));
135  }
136  }
137  desc.struct_float_count = i->struct_float_count();
138  uniforms_.push_back(std::move(desc));
139  }
140  }
141 
142  code_mapping_ = std::make_shared<fml::NonOwnedMapping>(
143  runtime_stage->shader()->data(), //
144  runtime_stage->shader()->size(), //
145  [payload = payload_](auto, auto) {} //
146  );
147 
148  size_t binding = 64;
149  if (ubo_id.has_value() && ubo_id.value() == binding) {
150  binding++;
151  }
152  for (auto& uniform : uniforms_) {
153  if (uniform.type == kSampledImage) {
154  uniform.binding = binding;
155  binding++;
156  if (ubo_id.has_value() && ubo_id.value() == binding) {
157  binding++;
158  }
159  }
160  }
161 
162  for (const auto& uniform : GetUniforms()) {
163  if (uniform.type == kStruct) {
164  descriptor_set_layouts_.push_back(DescriptorSetLayout{
165  static_cast<uint32_t>(uniform.location),
168  });
169  } else if (uniform.type == kSampledImage) {
170  descriptor_set_layouts_.push_back(DescriptorSetLayout{
171  static_cast<uint32_t>(uniform.binding),
174  });
175  }
176  }
177  is_valid_ = true;
178 }
179 
180 RuntimeStage::~RuntimeStage() = default;
183 
184 bool RuntimeStage::IsValid() const {
185  return is_valid_;
186 }
187 
188 const std::shared_ptr<fml::Mapping>& RuntimeStage::GetCodeMapping() const {
189  return code_mapping_;
190 }
191 
192 const std::vector<RuntimeUniformDescription>& RuntimeStage::GetUniforms()
193  const {
194  return uniforms_;
195 }
196 
198  const std::string& name) const {
199  for (const auto& uniform : uniforms_) {
200  if (uniform.name == name) {
201  return &uniform;
202  }
203  }
204  return nullptr;
205 }
206 
207 const std::string& RuntimeStage::GetEntrypoint() const {
208  return entrypoint_;
209 }
210 
212  return stage_;
213 }
214 
215 bool RuntimeStage::IsDirty() const {
216  return is_dirty_;
217 }
218 
220  is_dirty_ = false;
221 }
222 
223 const std::vector<DescriptorSetLayout>& RuntimeStage::GetDescriptorSetLayouts()
224  const {
225  return descriptor_set_layouts_;
226 }
227 
228 } // namespace impeller
GLenum type
const std::string & GetEntrypoint() const
RuntimeStage & operator=(RuntimeStage &&)
const std::vector< RuntimeUniformDescription > & GetUniforms() const
const RuntimeUniformDescription * GetUniform(const std::string &name) const
std::map< RuntimeStageBackend, std::shared_ptr< RuntimeStage > > Map
Definition: runtime_stage.h:25
static const char * kVulkanUBOName
Definition: runtime_stage.h:23
const std::shared_ptr< fml::Mapping > & GetCodeMapping() const
const std::vector< DescriptorSetLayout > & GetDescriptorSetLayouts() const
static absl::StatusOr< Map > DecodeRuntimeStages(const std::shared_ptr< fml::Mapping > &payload)
RuntimeShaderStage GetShaderStage() const
RuntimeStage(const fb::RuntimeStage *runtime_stage, const std::shared_ptr< fml::Mapping > &payload)
constexpr ShaderStage ToShaderStage(RuntimeShaderStage stage)
Definition: shader_types.h:29
static RuntimeUniformType ToType(fb::UniformDataType type)
RuntimeUniformDimensions dimensions
Definition: runtime_types.h:47
std::vector< uint8_t > struct_layout
Definition: runtime_types.h:50
std::optional< size_t > array_elements
Definition: runtime_types.h:49
size_t binding
Location, but for Vulkan.
Definition: runtime_types.h:45
const size_t end