| 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
5 #include "impeller/renderer/backend/metal/shader_library_mtl.h"
6
7 #include "flutter/fml/closure.h"
8 #include "impeller/base/validation.h"
9 #include "impeller/renderer/backend/metal/shader_function_mtl.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::kTessellationControl:
36 case ShaderStage::kTessellationEvaluation:
37 case ShaderStage::kCompute:
38 return MTLFunctionTypeKernel;
39 }
40 FML_UNREACHABLE();
41 }
42
43 std::shared_ptr<const ShaderFunction> ShaderLibraryMTL::GetFunction(
44 std::string_view name,
45 ShaderStage stage) {
46 if (!IsValid()) {
47 return nullptr;
48 }
49
50 if (name.empty()) {
51 VALIDATION_LOG << "Library function name was empty.";
52 return nullptr;
53 }
54
55 ShaderKey key(name, stage);
56
57 id<MTLFunction> function = nil;
58
59 {
60 ReaderLock lock(libraries_mutex_);
61
62 if (auto found = functions_.find(key); found != functions_.end()) {
63 return found->second;
64 }
65
66 for (size_t i = 0, count = [libraries_ count]; i < count; i++) {
67 function = [libraries_[i] 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, {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
impeller::ShaderLibraryMTL::~ShaderLibraryMTL
~ShaderLibraryMTL() override
impeller::ShaderStage::kUnknown
@ kUnknown
impeller::ToMTLFunctionType
static MTLFunctionType ToMTLFunctionType(ShaderStage stage)
Definition: shader_library_mtl.mm:28
impeller::ShaderStage
ShaderStage
Definition: shader_types.h:20
validation.h
shader_function_mtl.h
shader_library_mtl.h
impeller::ShaderStage::kTessellationEvaluation
@ kTessellationEvaluation
impeller::ShaderStage::kFragment
@ kFragment
impeller::ShaderLibraryMTL::ShaderLibraryMTL
ShaderLibraryMTL()
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
impeller::ShaderStage::kVertex
@ kVertex
impeller::ShaderStage::kCompute
@ kCompute
impeller::ShaderStage::kTessellationControl
@ kTessellationControl
impeller
Definition: aiks_context.cc:10
impeller::ShaderLibraryMTL::IsValid
bool IsValid() const override
Definition: shader_library_mtl.mm:24