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{library_data};
71  if (!blob_library.IsValid()) {
72  VALIDATION_LOG << "Could not construct shader blob library.";
73  return;
74  }
75  blob_library.IterateAllShaders(iterator);
76  }
77 
78  if (!success) {
79  VALIDATION_LOG << "Could not create shader modules for all shader blobs.";
80  return;
81  }
82  is_valid_ = true;
83 }
84 
85 ShaderLibraryVK::~ShaderLibraryVK() = default;
86 
87 bool ShaderLibraryVK::IsValid() const {
88  return is_valid_;
89 }
90 
91 // |ShaderLibrary|
92 std::shared_ptr<const ShaderFunction> ShaderLibraryVK::GetFunction(
93  std::string_view name,
94  ShaderStage stage) {
95  ReaderLock lock(functions_mutex_);
96 
97  const auto key = ShaderKey{{name.data(), name.size()}, stage};
98  auto found = functions_.find(key);
99  if (found != functions_.end()) {
100  return found->second;
101  }
102  return nullptr;
103 }
104 
105 // |ShaderLibrary|
106 void ShaderLibraryVK::RegisterFunction(std::string name,
107  ShaderStage stage,
108  std::shared_ptr<fml::Mapping> code,
109  RegistrationCallback callback) {
110  const auto result = RegisterFunction(name, stage, code);
111  if (callback) {
112  callback(result);
113  }
114 }
115 
116 static bool IsMappingSPIRV(const fml::Mapping& mapping) {
117  // https://registry.khronos.org/SPIR-V/specs/1.0/SPIRV.html#Magic
118  const uint32_t kSPIRVMagic = 0x07230203;
119  if (mapping.GetSize() < sizeof(kSPIRVMagic)) {
120  return false;
121  }
122  uint32_t magic = 0u;
123  ::memcpy(&magic, mapping.GetMapping(), sizeof(magic));
124  return magic == kSPIRVMagic;
125 }
126 
127 bool ShaderLibraryVK::RegisterFunction(
128  const std::string& name,
129  ShaderStage stage,
130  const std::shared_ptr<fml::Mapping>& code) {
131  if (!code) {
132  return false;
133  }
134 
135  if (!IsMappingSPIRV(*code)) {
136  VALIDATION_LOG << "Shader is not valid SPIRV.";
137  return false;
138  }
139 
140  vk::ShaderModuleCreateInfo shader_module_info;
141 
142  shader_module_info.setPCode(
143  reinterpret_cast<const uint32_t*>(code->GetMapping()));
144  shader_module_info.setCodeSize(code->GetSize());
145 
146  auto device_holder = device_holder_.lock();
147  if (!device_holder) {
148  return false;
149  }
150  FML_DCHECK(device_holder->GetDevice());
151  auto module =
152  device_holder->GetDevice().createShaderModuleUnique(shader_module_info);
153 
154  if (module.result != vk::Result::eSuccess) {
155  VALIDATION_LOG << "Could not create shader module: "
156  << vk::to_string(module.result);
157  return false;
158  }
159 
160  vk::UniqueShaderModule shader_module = std::move(module.value);
161  ContextVK::SetDebugName(device_holder->GetDevice(), *shader_module,
162  "Shader " + name);
163 
164  WriterLock lock(functions_mutex_);
165  functions_[ShaderKey{name, stage}] = std::shared_ptr<ShaderFunctionVK>(
166  new ShaderFunctionVK(device_holder_,
167  library_id_, //
168  name, //
169  stage, //
170  std::move(shader_module) //
171  ));
172 
173  return true;
174 }
175 
176 // |ShaderLibrary|
177 void ShaderLibraryVK::UnregisterFunction(std::string name, ShaderStage stage) {
178  WriterLock lock(functions_mutex_);
179 
180  const auto key = ShaderKey{name, stage};
181 
182  auto found = functions_.find(key);
183  if (found == functions_.end()) {
184  VALIDATION_LOG << "Library function named " << name
185  << " was not found, so it couldn't be unregistered.";
186  return;
187  }
188 
189  functions_.erase(found);
190 
191  return;
192 }
193 
194 } // namespace impeller
GLenum type
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