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 absl::StatusOr<RuntimeStage> RuntimeStage::Create(
52  const fb::RuntimeStage* runtime_stage,
53  const std::shared_ptr<fml::Mapping>& payload) {
54  if (!runtime_stage) {
55  return absl::InvalidArgumentError("Runtime stage is null.");
56  }
57 
58  RuntimeStage stage(payload);
59  stage.stage_ = ToShaderStage(runtime_stage->stage());
60  stage.entrypoint_ = runtime_stage->entrypoint()->str();
61 
62  auto* uniforms = runtime_stage->uniforms();
63 
64  // Note: image bindings are screwy and will always have the same offset.
65  // track the binding of the UBO to determine where the image bindings go.
66  // This is only guaranteed to give us the correct bindings if there is a
67  // single sampler2D.
68  std::optional<size_t> ubo_id;
69  if (uniforms) {
70  for (auto i = uniforms->begin(), end = uniforms->end(); i != end; i++) {
72  desc.name = i->name()->str();
73  desc.location = i->location();
74  desc.binding = i->binding();
75  desc.type = ToType(i->type());
76  if (desc.type == kStruct) {
77  ubo_id = desc.location;
78  desc.binding = desc.location;
79  }
81  static_cast<size_t>(i->rows()), static_cast<size_t>(i->columns())};
82  desc.bit_width = i->bit_width();
83  desc.array_elements = i->array_elements();
84  if (i->padding_layout()) {
85  for (const auto& byte_type : *i->padding_layout()) {
87  switch (byte_type) {
90  break;
93  break;
94  }
95  desc.padding_layout.push_back(type);
96  }
97  }
98  if (i->struct_fields()) {
99  for (const auto& elem : *i->struct_fields()) {
100  desc.struct_fields.emplace_back(
101  StructField{.name = elem->name()->str(),
102  .byte_size = static_cast<size_t>(elem->byte_size())});
103  }
104  }
105  desc.struct_float_count = i->struct_float_count();
106  stage.uniforms_.push_back(std::move(desc));
107  }
108  }
109 
110  stage.code_mapping_ = std::make_shared<fml::NonOwnedMapping>(
111  runtime_stage->shader()->data(), //
112  runtime_stage->shader()->size(), //
113  [payload = stage.payload_](auto, auto) {} //
114  );
115 
116  size_t binding = 64;
117  if (ubo_id.has_value() && ubo_id.value() == binding) {
118  binding++;
119  }
120  for (auto& uniform : stage.uniforms_) {
121  if (uniform.type == kSampledImage) {
122  uniform.binding = binding;
123  binding++;
124  if (ubo_id.has_value() && ubo_id.value() == binding) {
125  binding++;
126  }
127  }
128  }
129 
130  for (const auto& uniform : stage.GetUniforms()) {
131  if (uniform.type == kStruct) {
132  stage.descriptor_set_layouts_.push_back(DescriptorSetLayout{
133  static_cast<uint32_t>(uniform.location),
136  });
137  } else if (uniform.type == kSampledImage) {
138  stage.descriptor_set_layouts_.push_back(DescriptorSetLayout{
139  static_cast<uint32_t>(uniform.binding),
142  });
143  }
144  }
145 
146  return stage;
147 }
148 
149 std::unique_ptr<RuntimeStage> RuntimeStage::RuntimeStageIfPresent(
150  const fb::RuntimeStage* runtime_stage,
151  const std::shared_ptr<fml::Mapping>& payload) {
152  auto stage = Create(runtime_stage, payload);
153  if (!stage.ok()) {
154  return nullptr;
155  }
156  return std::make_unique<RuntimeStage>(std::move(*stage));
157 }
158 
159 absl::StatusOr<RuntimeStage::Map> RuntimeStage::DecodeRuntimeStages(
160  const std::shared_ptr<fml::Mapping>& payload) {
161  if (payload == nullptr || !payload->GetMapping()) {
162  return absl::InvalidArgumentError("Payload is null or empty.");
163  }
164  if (!fb::RuntimeStagesBufferHasIdentifier(payload->GetMapping())) {
165  return absl::InvalidArgumentError(
166  "Payload does not have valid identifier.");
167  }
168 
169  auto raw_stages = fb::GetRuntimeStages(payload->GetMapping());
170  if (!raw_stages) {
171  return absl::InvalidArgumentError("Failed to get runtime stages.");
172  }
173 
174  const uint32_t version = raw_stages->format_version();
175  const auto expected =
176  static_cast<uint32_t>(fb::RuntimeStagesFormatVersion::kVersion);
177  if (version != expected) {
178  std::stringstream stream;
179  stream << "Unsupported runtime stages format version. Expected " << expected
180  << ", got " << version << ".";
181  return absl::InvalidArgumentError(stream.str());
182  }
183 
184  return Map{
186  RuntimeStageIfPresent(raw_stages->sksl(), payload)},
188  RuntimeStageIfPresent(raw_stages->metal(), payload)},
190  RuntimeStageIfPresent(raw_stages->opengles(), payload)},
192  RuntimeStageIfPresent(raw_stages->opengles3(), payload)},
194  RuntimeStageIfPresent(raw_stages->vulkan(), payload)},
195  };
196 }
197 
198 RuntimeStage::RuntimeStage(std::shared_ptr<fml::Mapping> payload)
199  : payload_(std::move(payload)) {}
200 
201 RuntimeStage::~RuntimeStage() = default;
202 RuntimeStage::RuntimeStage(RuntimeStage&&) = default;
203 RuntimeStage& RuntimeStage::operator=(RuntimeStage&&) = default;
204 
205 const std::shared_ptr<fml::Mapping>& RuntimeStage::GetCodeMapping() const {
206  return code_mapping_;
207 }
208 
209 const std::vector<RuntimeUniformDescription>& RuntimeStage::GetUniforms()
210  const {
211  return uniforms_;
212 }
213 
215  const std::string& name) const {
216  for (const auto& uniform : uniforms_) {
217  if (uniform.name == name) {
218  return &uniform;
219  }
220  }
221  return nullptr;
222 }
223 
224 const std::string& RuntimeStage::GetEntrypoint() const {
225  return entrypoint_;
226 }
227 
229  return stage_;
230 }
231 
232 bool RuntimeStage::IsDirty() const {
233  return is_dirty_;
234 }
235 
237  is_dirty_ = false;
238 }
239 
240 const std::vector<DescriptorSetLayout>& RuntimeStage::GetDescriptorSetLayouts()
241  const {
242  return descriptor_set_layouts_;
243 }
244 
245 } // namespace impeller
GLenum type
RuntimeStage(RuntimeStage &&)
const std::string & GetEntrypoint() const
RuntimeStage & operator=(RuntimeStage &&)
static absl::StatusOr< RuntimeStage > Create(const fb::RuntimeStage *runtime_stage, const std::shared_ptr< fml::Mapping > &payload)
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
constexpr ShaderStage ToShaderStage(RuntimeShaderStage stage)
Definition: shader_types.h:29
static RuntimeUniformType ToType(fb::UniformDataType type)
constexpr auto kPadding
Definition: comparable.h:95
RuntimeUniformDimensions dimensions
Definition: runtime_types.h:58
std::vector< StructField > struct_fields
Definition: runtime_types.h:64
std::vector< RuntimePaddingType > padding_layout
Definition: runtime_types.h:61
std::optional< size_t > array_elements
Definition: runtime_types.h:60
size_t binding
Location, but for Vulkan.
Definition: runtime_types.h:56
const size_t end