1 /* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #include "tensorflow/lite/delegates/external/external_delegate.h"
16
17 #include <locale>
18 #include <string>
19 #include <vector>
20
21 #include "tensorflow/lite/minimal_logging.h"
22 #include "tensorflow/lite/shared_library.h"
23
24 namespace tflite {
25 namespace {
26
27 // External delegate library construct
28 struct ExternalLib {
29 using CreateDelegatePtr = std::add_pointer<TfLiteDelegate*(
30 const char**, const char**, size_t,
31 void (*report_error)(const char*))>::type;
32 using DestroyDelegatePtr = std::add_pointer<void(TfLiteDelegate*)>::type;
33 struct wchar_codecvt : public std::codecvt<wchar_t, char, std::mbstate_t> {};
34
35 // Open a given delegate library and load the create/destroy symbols
loadtflite::__anon7d121f280111::ExternalLib36 bool load(const std::string library) {
37 #if defined(_WIN32)
38 std::wstring_convert<wchar_codecvt> converter;
39 void* handle = SharedLibrary::LoadLibrary(
40 converter.from_bytes(library.c_str()).c_str());
41 #else
42 void* handle = SharedLibrary::LoadLibrary(library.c_str());
43 #endif // defined(_WIN32)
44 if (handle == nullptr) {
45 TFLITE_LOG(TFLITE_LOG_INFO, "Unable to load external delegate from : %s",
46 library.c_str());
47 } else {
48 create =
49 reinterpret_cast<decltype(create)>(SharedLibrary::GetLibrarySymbol(
50 handle, "tflite_plugin_create_delegate"));
51 destroy =
52 reinterpret_cast<decltype(destroy)>(SharedLibrary::GetLibrarySymbol(
53 handle, "tflite_plugin_destroy_delegate"));
54 return create && destroy;
55 }
56 return false;
57 }
58
59 CreateDelegatePtr create{nullptr};
60 DestroyDelegatePtr destroy{nullptr};
61 };
62
63 // An ExternalDelegateWrapper is responsibile to manage a TFLite delegate
64 // initialized from a shared library. It creates a delegate from the given
65 // option and storages it to external_delegate_ member variable. On the
66 // destruction, it conducts necessary clean up process.
67 class ExternalDelegateWrapper {
68 public:
69 explicit ExternalDelegateWrapper(
70 const TfLiteExternalDelegateOptions* options);
71 ~ExternalDelegateWrapper();
72
73 // Return a TfLiteDelegate which is created from
74 // tflite_plugin_create_delegate() of an external delegate logic.
tflite_external_delegate()75 TfLiteDelegate* tflite_external_delegate() { return external_delegate_; }
76
77 // Return a TfLiteDelegate which is convertibile to this class.
tflite_wrapper_delegate()78 TfLiteDelegate* tflite_wrapper_delegate() { return &wrapper_delegate_; }
79
80 private:
81 ExternalLib external_lib_;
82
83 // external delegate instance owned by external delegate logic.
84 // It's created by "tflite_plugin_destroy_delegate()" function in the external
85 // delegate logic And it should be released by
86 // "tflite_plugin_destroy_delegate()" function.
87 TfLiteDelegate* external_delegate_;
88
89 // TfLiteDelegate representation of this ExternalDelegateWrapper object.
90 TfLiteDelegate wrapper_delegate_;
91 };
92
93 // Converts the given TfLiteDelegate to an ExternalDelegateWrapper instance.
GetExternalDelegateWrapper(TfLiteDelegate * delegate)94 inline ExternalDelegateWrapper* GetExternalDelegateWrapper(
95 TfLiteDelegate* delegate) {
96 return reinterpret_cast<ExternalDelegateWrapper*>(delegate->data_);
97 }
98
99 // Relay Prepare() call to the associated external TfLiteDelegate object.
DelegatePrepare(TfLiteContext * context,TfLiteDelegate * delegate)100 TfLiteStatus DelegatePrepare(TfLiteContext* context, TfLiteDelegate* delegate) {
101 auto external_delegate_wrapper = GetExternalDelegateWrapper(delegate);
102 TfLiteDelegate* external_delegate =
103 external_delegate_wrapper->tflite_external_delegate();
104 return external_delegate->Prepare(context, external_delegate);
105 }
106
107 // Relay CopyFromBufferHandle() call to the associated external TfLiteDelegate
108 // object.
DelegateCopyFromBufferHandle(TfLiteContext * context,struct TfLiteDelegate * delegate,TfLiteBufferHandle buffer_handle,TfLiteTensor * tensor)109 TfLiteStatus DelegateCopyFromBufferHandle(TfLiteContext* context,
110 struct TfLiteDelegate* delegate,
111 TfLiteBufferHandle buffer_handle,
112 TfLiteTensor* tensor) {
113 auto external_delegate_wrapper = GetExternalDelegateWrapper(delegate);
114 TfLiteDelegate* external_delegate =
115 external_delegate_wrapper->tflite_external_delegate();
116 return external_delegate->CopyFromBufferHandle(context, delegate,
117 buffer_handle, tensor);
118 }
119
120 // Relay CopyToBufferHandle() call to the associated external TfLiteDelegate
121 // object.
DelegateCopyToBufferHandle(TfLiteContext * context,struct TfLiteDelegate * delegate,TfLiteBufferHandle buffer_handle,TfLiteTensor * tensor)122 TfLiteStatus DelegateCopyToBufferHandle(TfLiteContext* context,
123 struct TfLiteDelegate* delegate,
124 TfLiteBufferHandle buffer_handle,
125 TfLiteTensor* tensor) {
126 auto external_delegate_wrapper = GetExternalDelegateWrapper(delegate);
127 TfLiteDelegate* external_delegate =
128 external_delegate_wrapper->tflite_external_delegate();
129 return external_delegate->CopyToBufferHandle(context, delegate, buffer_handle,
130 tensor);
131 }
132
133 // Relay FreeBufferHandle() call to the associated external TfLiteDelegate
134 // object.
DelegateFreeBufferHandle(TfLiteContext * context,struct TfLiteDelegate * delegate,TfLiteBufferHandle * handle)135 void DelegateFreeBufferHandle(TfLiteContext* context,
136 struct TfLiteDelegate* delegate,
137 TfLiteBufferHandle* handle) {
138 auto external_delegate_wrapper = GetExternalDelegateWrapper(delegate);
139 TfLiteDelegate* external_delegate =
140 external_delegate_wrapper->tflite_external_delegate();
141 return external_delegate->FreeBufferHandle(context, delegate, handle);
142 }
143
ExternalDelegateWrapper(const TfLiteExternalDelegateOptions * options)144 ExternalDelegateWrapper::ExternalDelegateWrapper(
145 const TfLiteExternalDelegateOptions* options) {
146 external_delegate_ = nullptr;
147 if (external_lib_.load(options->lib_path)) {
148 std::vector<const char*> ckeys, cvalues;
149 for (int i = 0; i < options->count; i++) {
150 ckeys.push_back(options->keys[i]);
151 cvalues.push_back(options->values[i]);
152 }
153
154 external_delegate_ = external_lib_.create(ckeys.data(), cvalues.data(),
155 ckeys.size(), nullptr);
156 if (external_delegate_) {
157 wrapper_delegate_ = {
158 reinterpret_cast<void*>(this), // .data =
159 DelegatePrepare, // .Prepare =
160 nullptr, // .CopyFromBufferHandle =
161 nullptr, // .CopyToBufferHandle =
162 nullptr, // .FreeBufferHandle =
163 external_delegate_->flags, // .flags =
164 };
165 if (external_delegate_->CopyFromBufferHandle) {
166 wrapper_delegate_.CopyFromBufferHandle = DelegateCopyFromBufferHandle;
167 }
168 if (external_delegate_->CopyToBufferHandle) {
169 wrapper_delegate_.CopyToBufferHandle = DelegateCopyToBufferHandle;
170 }
171 if (external_delegate_->FreeBufferHandle) {
172 wrapper_delegate_.FreeBufferHandle = DelegateFreeBufferHandle;
173 }
174 }
175 }
176 }
177
~ExternalDelegateWrapper()178 ExternalDelegateWrapper::~ExternalDelegateWrapper() {
179 if (external_delegate_ != nullptr) {
180 external_lib_.destroy(external_delegate_);
181 }
182 }
183
184 } // namespace
185 } // namespace tflite
186
187 // TfLiteExternalDelegateOptionsInsert adds key/value to the given
188 // TfLiteExternalDelegateOptions instance.
TfLiteExternalDelegateOptionsInsert(TfLiteExternalDelegateOptions * options,const char * key,const char * value)189 TfLiteStatus TfLiteExternalDelegateOptionsInsert(
190 TfLiteExternalDelegateOptions* options, const char* key,
191 const char* value) {
192 if (options->count >= kExternalDelegateMaxOptions) {
193 return kTfLiteError;
194 }
195 options->keys[options->count] = key;
196 options->values[options->count] = value;
197 options->count++;
198 return kTfLiteOk;
199 }
200
TfLiteExternalDelegateOptionsDefault(const char * lib_path)201 TfLiteExternalDelegateOptions TfLiteExternalDelegateOptionsDefault(
202 const char* lib_path) {
203 // As 'keys' and 'values' don't need to be set here, using designated
204 // initializers may cause a compiling error as "non-trivial designated
205 // initializers not supported" by some compiler.
206 TfLiteExternalDelegateOptions options;
207 options.lib_path = lib_path;
208 options.count = 0;
209 options.insert = TfLiteExternalDelegateOptionsInsert;
210 return options;
211 }
212
TfLiteExternalDelegateCreate(const TfLiteExternalDelegateOptions * options)213 TfLiteDelegate* TfLiteExternalDelegateCreate(
214 const TfLiteExternalDelegateOptions* options) {
215 auto* external_delegate_wrapper =
216 new tflite::ExternalDelegateWrapper(options);
217 if (external_delegate_wrapper) {
218 return external_delegate_wrapper->tflite_wrapper_delegate();
219 }
220 return nullptr;
221 }
222
TfLiteExternalDelegateDelete(TfLiteDelegate * delegate)223 void TfLiteExternalDelegateDelete(TfLiteDelegate* delegate) {
224 delete tflite::GetExternalDelegateWrapper(delegate);
225 }
226