Flutter Impeller
shader_library_mtl.mm
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 "flutter/fml/closure.h"
10 
11 namespace impeller {
12 
13 ShaderLibraryMTL::ShaderLibraryMTL(NSArray<id<MTLLibrary>>* libraries)
14  : libraries_([libraries mutableCopy]) {
15  if (libraries_ == nil || libraries_.count == 0) {
16  return;
17  }
18 
19  is_valid_ = true;
20 }
21 
22 ShaderLibraryMTL::~ShaderLibraryMTL() = default;
23 
24 bool ShaderLibraryMTL::IsValid() const {
25  return is_valid_;
26 }
27 
28 static MTLFunctionType ToMTLFunctionType(ShaderStage stage) {
29  switch (stage) {
30  case ShaderStage::kVertex:
31  return MTLFunctionTypeVertex;
32  case ShaderStage::kFragment:
33  return MTLFunctionTypeFragment;
34  case ShaderStage::kUnknown:
35  case ShaderStage::kCompute:
36  return MTLFunctionTypeKernel;
37  }
38  FML_UNREACHABLE();
39 }
40 
41 std::shared_ptr<const ShaderFunction> ShaderLibraryMTL::GetFunction(
42  std::string_view name,
43  ShaderStage stage) {
44  if (!IsValid()) {
45  return nullptr;
46  }
47 
48  if (name.empty()) {
49  VALIDATION_LOG << "Library function name was empty.";
50  return nullptr;
51  }
52 
53  ShaderKey key(name, stage);
54 
55  id<MTLFunction> function = nil;
56  id<MTLLibrary> library = nil;
57 
58  {
59  ReaderLock lock(libraries_mutex_);
60 
61  if (auto found = functions_.find(key); found != functions_.end()) {
62  return found->second;
63  }
64 
65  for (size_t i = 0, count = [libraries_ count]; i < count; i++) {
66  library = libraries_[i];
67  function = [library newFunctionWithName:@(name.data())];
68  if (function) {
69  break;
70  }
71  }
72 
73  if (function == nil) {
74  return nullptr;
75  }
76 
77  if (function.functionType != ToMTLFunctionType(stage)) {
78  VALIDATION_LOG << "Library function named " << name
79  << " was for an unexpected shader stage.";
80  return nullptr;
81  }
82 
83  auto func = std::shared_ptr<ShaderFunctionMTL>(new ShaderFunctionMTL(
84  library_id_, function, library, {name.data(), name.size()}, stage));
85  functions_[key] = func;
86 
87  return func;
88  }
89 }
90 
91 id<MTLDevice> ShaderLibraryMTL::GetDevice() const {
92  ReaderLock lock(libraries_mutex_);
93  if (libraries_.count > 0u) {
94  return libraries_[0].device;
95  }
96  return nil;
97 }
98 
99 // |ShaderLibrary|
100 void ShaderLibraryMTL::RegisterFunction(std::string name, // unused
101  ShaderStage stage, // unused
102  std::shared_ptr<fml::Mapping> code,
103  RegistrationCallback callback) {
104  if (!callback) {
105  callback = [](auto) {};
106  }
107  auto failure_callback = std::make_shared<fml::ScopedCleanupClosure>(
108  [callback]() { callback(false); });
109  if (!IsValid()) {
110  return;
111  }
112  if (code == nullptr || code->GetMapping() == nullptr) {
113  return;
114  }
115  auto device = GetDevice();
116  if (device == nil) {
117  return;
118  }
119 
120  auto source = [[NSString alloc] initWithBytes:code->GetMapping()
121  length:code->GetSize()
122  encoding:NSUTF8StringEncoding];
123 
124  auto weak_this = weak_from_this();
125  [device newLibraryWithSource:source
126  options:NULL
127  completionHandler:^(id<MTLLibrary> library, NSError* error) {
128  auto strong_this = weak_this.lock();
129  if (!strong_this) {
130  VALIDATION_LOG << "Shader library was collected before "
131  "dynamic shader stage could be registered.";
132  return;
133  }
134  if (!library) {
135  VALIDATION_LOG << "Could not register dynamic stage library: "
136  << error.localizedDescription.UTF8String;
137  return;
138  }
139  reinterpret_cast<ShaderLibraryMTL*>(strong_this.get())
140  ->RegisterLibrary(library);
141  failure_callback->Release();
142  callback(true);
143  }];
144 }
145 
146 // |ShaderLibrary|
147 void ShaderLibraryMTL::UnregisterFunction(std::string name, ShaderStage stage) {
148  ReaderLock lock(libraries_mutex_);
149 
150  // Find the shader library containing this function name and remove it.
151 
152  bool found_library = false;
153  for (size_t i = [libraries_ count] - 1; i >= 0; i--) {
154  id<MTLFunction> function =
155  [libraries_[i] newFunctionWithName:@(name.data())];
156  if (function) {
157  [libraries_ removeObjectAtIndex:i];
158  found_library = true;
159  break;
160  }
161  }
162  if (!found_library) {
163  VALIDATION_LOG << "Library containing function " << name
164  << " was not found, so it couldn't be unregistered.";
165  }
166 
167  // Remove the shader from the function cache.
168 
169  ShaderKey key(name, stage);
170 
171  auto found = functions_.find(key);
172  if (found == functions_.end()) {
173  VALIDATION_LOG << "Library function named " << name
174  << " was not found, so it couldn't be unregistered.";
175  return;
176  }
177 
178  functions_.erase(found);
179 }
180 
181 void ShaderLibraryMTL::RegisterLibrary(id<MTLLibrary> library) {
182  WriterLock lock(libraries_mutex_);
183  [libraries_ addObject:library];
184 }
185 
186 } // namespace impeller
static MTLFunctionType ToMTLFunctionType(ShaderStage stage)
#define VALIDATION_LOG
Definition: validation.h:91