Flutter Impeller
shader_library_vk.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 <cstdint>
8 
9 #include "flutter/fml/logging.h"
10 #include "flutter/fml/trace_event.h"
14 
15 namespace impeller {
16 
18  switch (type) {
20  return ShaderStage::kVertex;
24  return ShaderStage::kCompute;
25  }
26  FML_UNREACHABLE();
27 }
28 
29 static std::string VKShaderNameToShaderKeyName(const std::string& name,
30  ShaderStage stage) {
31  std::stringstream stream;
32  stream << name;
33  switch (stage) {
35  stream << "_unknown_";
36  break;
38  stream << "_vertex_";
39  break;
41  stream << "_fragment_";
42  break;
44  stream << "_compute_";
45  break;
46  }
47  stream << "main";
48  return stream.str();
49 }
50 
51 ShaderLibraryVK::ShaderLibraryVK(
52  std::weak_ptr<DeviceHolderVK> device_holder,
53  const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data)
54  : device_holder_(std::move(device_holder)) {
55  TRACE_EVENT0("impeller", "CreateShaderLibrary");
56  bool success = true;
57  auto iterator = [&](auto type, //
58  const auto& name, //
59  const auto& code //
60  ) -> bool {
61  const auto stage = ToShaderStage(type);
62  if (!RegisterFunction(VKShaderNameToShaderKeyName(name, stage), stage,
63  code)) {
64  success = false;
65  return false;
66  }
67  return true;
68  };
69  for (const auto& library_data : shader_libraries_data) {
70  auto blob_library = ShaderArchive::Create(library_data);
71  if (!blob_library.ok()) {
72  VALIDATION_LOG << "Could not construct shader blob library: "
73  << blob_library.status().ToString();
74  return;
75  }
76  blob_library->IterateAllShaders(iterator);
77  }
78 
79  if (!success) {
80  VALIDATION_LOG << "Could not create shader modules for all shader blobs.";
81  return;
82  }
83  is_valid_ = true;
84 }
85 
86 ShaderLibraryVK::~ShaderLibraryVK() = default;
87 
88 bool ShaderLibraryVK::IsValid() const {
89  return is_valid_;
90 }
91 
92 // |ShaderLibrary|
93 std::shared_ptr<const ShaderFunction> ShaderLibraryVK::GetFunction(
94  std::string_view name,
95  ShaderStage stage) {
96  ReaderLock lock(functions_mutex_);
97 
98  const auto key = ShaderKey{{name.data(), name.size()}, stage};
99  auto found = functions_.find(key);
100  if (found != functions_.end()) {
101  return found->second;
102  }
103  return nullptr;
104 }
105 
106 // |ShaderLibrary|
107 void ShaderLibraryVK::RegisterFunction(std::string name,
108  ShaderStage stage,
109  std::shared_ptr<fml::Mapping> code,
110  RegistrationCallback callback) {
111  const auto result = RegisterFunction(name, stage, code);
112  if (callback) {
113  callback(result);
114  }
115 }
116 
117 static bool IsMappingSPIRV(const fml::Mapping& mapping) {
118  // https://registry.khronos.org/SPIR-V/specs/1.0/SPIRV.html#Magic
119  const uint32_t kSPIRVMagic = 0x07230203;
120  if (mapping.GetSize() < sizeof(kSPIRVMagic)) {
121  return false;
122  }
123  uint32_t magic = 0u;
124  ::memcpy(&magic, mapping.GetMapping(), sizeof(magic));
125  return magic == kSPIRVMagic;
126 }
127 
128 bool ShaderLibraryVK::RegisterFunction(
129  const std::string& name,
130  ShaderStage stage,
131  const std::shared_ptr<fml::Mapping>& code) {
132  if (!code) {
133  return false;
134  }
135 
136  if (!IsMappingSPIRV(*code)) {
137  VALIDATION_LOG << "Shader is not valid SPIRV.";
138  return false;
139  }
140 
141  vk::ShaderModuleCreateInfo shader_module_info;
142 
143  shader_module_info.setPCode(
144  reinterpret_cast<const uint32_t*>(code->GetMapping()));
145  shader_module_info.setCodeSize(code->GetSize());
146 
147  auto device_holder = device_holder_.lock();
148  if (!device_holder) {
149  return false;
150  }
151  FML_DCHECK(device_holder->GetDevice());
152  auto module =
153  device_holder->GetDevice().createShaderModuleUnique(shader_module_info);
154 
155  if (module.result != vk::Result::eSuccess) {
156  VALIDATION_LOG << "Could not create shader module: "
157  << vk::to_string(module.result);
158  return false;
159  }
160 
161  vk::UniqueShaderModule shader_module = std::move(module.value);
162  ContextVK::SetDebugName(device_holder->GetDevice(), *shader_module,
163  "Shader " + name);
164 
165  WriterLock lock(functions_mutex_);
166  functions_[ShaderKey{name, stage}] = std::shared_ptr<ShaderFunctionVK>(
167  new ShaderFunctionVK(device_holder_,
168  library_id_, //
169  name, //
170  stage, //
171  std::move(shader_module) //
172  ));
173 
174  return true;
175 }
176 
177 // |ShaderLibrary|
178 void ShaderLibraryVK::UnregisterFunction(std::string name, ShaderStage stage) {
179  WriterLock lock(functions_mutex_);
180 
181  const auto key = ShaderKey{name, stage};
182 
183  auto found = functions_.find(key);
184  if (found == functions_.end()) {
185  VALIDATION_LOG << "Library function named " << name
186  << " was not found, so it couldn't be unregistered.";
187  return;
188  }
189 
190  functions_.erase(found);
191 
192  return;
193 }
194 
195 } // namespace impeller
GLenum type
static absl::StatusOr< ShaderArchive > Create(std::shared_ptr< fml::Mapping > payload)
constexpr ShaderStage ToShaderStage(RuntimeShaderStage stage)
Definition: shader_types.h:29
static bool IsMappingSPIRV(const fml::Mapping &mapping)
static std::string VKShaderNameToShaderKeyName(const std::string &name, ShaderStage stage)
Definition: comparable.h:95
#define VALIDATION_LOG
Definition: validation.h:91