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 <string>
18 #include <vector>
19
20 #include "tensorflow/lite/minimal_logging.h"
21 #include "tensorflow/lite/shared_library.h"
22
23 namespace tflite {
24 namespace {
25
26 // External delegate library construct
27 struct ExternalLib {
28 using CreateDelegatePtr = std::add_pointer<TfLiteDelegate*(
29 const char**, const char**, size_t,
30 void (*report_error)(const char*))>::type;
31 using DestroyDelegatePtr = std::add_pointer<void(TfLiteDelegate*)>::type;
32
33 // Open a given delegate library and load the create/destroy symbols
loadtflite::__anonbe5b70390111::ExternalLib34 bool load(const std::string library) {
35 void* handle = SharedLibrary::LoadLibrary(library.c_str());
36 if (handle == nullptr) {
37 TFLITE_LOG(TFLITE_LOG_INFO, "Unable to load external delegate from : %s",
38 library.c_str());
39 } else {
40 create =
41 reinterpret_cast<decltype(create)>(SharedLibrary::GetLibrarySymbol(
42 handle, "tflite_plugin_create_delegate"));
43 destroy =
44 reinterpret_cast<decltype(destroy)>(SharedLibrary::GetLibrarySymbol(
45 handle, "tflite_plugin_destroy_delegate"));
46 return create && destroy;
47 }
48 return false;
49 }
50
51 CreateDelegatePtr create{nullptr};
52 DestroyDelegatePtr destroy{nullptr};
53 };
54
55 // An ExternalDelegateWrapper is responsibile to manage a TFLite delegate
56 // initialized from a shared library. It creates a delegate from the given
57 // option and storages it to external_delegate_ member variable. On the
58 // destruction, it conducts necessary clean up process.
59 class ExternalDelegateWrapper {
60 public:
61 explicit ExternalDelegateWrapper(
62 const TfLiteExternalDelegateOptions* options);
63 ~ExternalDelegateWrapper();
64
65 // Return a TfLiteDelegate which is created from
66 // tflite_plugin_create_delegate() of an external delegate logic.
tflite_external_delegate()67 TfLiteDelegate* tflite_external_delegate() { return external_delegate_; }
68
69 // Return a TfLiteDelegate which is convertibile to this class.
tflite_wrapper_delegate()70 TfLiteDelegate* tflite_wrapper_delegate() { return &wrapper_delegate_; }
71
72 private:
73 ExternalLib external_lib_;
74
75 // external delegate instance owned by external delegate logic.
76 // It's created by "tflite_plugin_destroy_delegate()" function in the external
77 // delegate logic And it should be released by
78 // "tflite_plugin_destroy_delegate()" function.
79 TfLiteDelegate* external_delegate_;
80
81 // TfLiteDelegate representation of this ExternalDelegateWrapper object.
82 TfLiteDelegate wrapper_delegate_;
83 };
84
85 // Converts the given TfLiteDelegate to an ExternalDelegateWrapper instance.
GetExternalDelegateWrapper(TfLiteDelegate * delegate)86 inline ExternalDelegateWrapper* GetExternalDelegateWrapper(
87 TfLiteDelegate* delegate) {
88 return reinterpret_cast<ExternalDelegateWrapper*>(delegate->data_);
89 }
90
91 // Relay Prepare() call to the associated external TfLiteDelegate object.
DelegatePrepare(TfLiteContext * context,TfLiteDelegate * delegate)92 TfLiteStatus DelegatePrepare(TfLiteContext* context, TfLiteDelegate* delegate) {
93 auto external_delegate_wrapper = GetExternalDelegateWrapper(delegate);
94 TfLiteDelegate* external_delegate =
95 external_delegate_wrapper->tflite_external_delegate();
96 return external_delegate->Prepare(context, external_delegate);
97 }
98
99 // Relay CopyFromBufferHandle() call to the associated external TfLiteDelegate
100 // object.
DelegateCopyFromBufferHandle(TfLiteContext * context,struct TfLiteDelegate * delegate,TfLiteBufferHandle buffer_handle,TfLiteTensor * tensor)101 TfLiteStatus DelegateCopyFromBufferHandle(TfLiteContext* context,
102 struct TfLiteDelegate* delegate,
103 TfLiteBufferHandle buffer_handle,
104 TfLiteTensor* tensor) {
105 auto external_delegate_wrapper = GetExternalDelegateWrapper(delegate);
106 TfLiteDelegate* external_delegate =
107 external_delegate_wrapper->tflite_external_delegate();
108 return external_delegate->CopyFromBufferHandle(context, delegate,
109 buffer_handle, tensor);
110 }
111
112 // Relay CopyToBufferHandle() call to the associated external TfLiteDelegate
113 // object.
DelegateCopyToBufferHandle(TfLiteContext * context,struct TfLiteDelegate * delegate,TfLiteBufferHandle buffer_handle,TfLiteTensor * tensor)114 TfLiteStatus DelegateCopyToBufferHandle(TfLiteContext* context,
115 struct TfLiteDelegate* delegate,
116 TfLiteBufferHandle buffer_handle,
117 TfLiteTensor* tensor) {
118 auto external_delegate_wrapper = GetExternalDelegateWrapper(delegate);
119 TfLiteDelegate* external_delegate =
120 external_delegate_wrapper->tflite_external_delegate();
121 return external_delegate->CopyToBufferHandle(context, delegate, buffer_handle,
122 tensor);
123 }
124
125 // Relay FreeBufferHandle() call to the associated external TfLiteDelegate
126 // object.
DelegateFreeBufferHandle(TfLiteContext * context,struct TfLiteDelegate * delegate,TfLiteBufferHandle * handle)127 void DelegateFreeBufferHandle(TfLiteContext* context,
128 struct TfLiteDelegate* delegate,
129 TfLiteBufferHandle* handle) {
130 auto external_delegate_wrapper = GetExternalDelegateWrapper(delegate);
131 TfLiteDelegate* external_delegate =
132 external_delegate_wrapper->tflite_external_delegate();
133 return external_delegate->FreeBufferHandle(context, delegate, handle);
134 }
135
ExternalDelegateWrapper(const TfLiteExternalDelegateOptions * options)136 ExternalDelegateWrapper::ExternalDelegateWrapper(
137 const TfLiteExternalDelegateOptions* options) {
138 external_delegate_ = nullptr;
139 if (external_lib_.load(options->lib_path)) {
140 std::vector<const char*> ckeys, cvalues;
141 for (int i = 0; i < options->count; i++) {
142 ckeys.push_back(options->keys[i]);
143 cvalues.push_back(options->values[i]);
144 }
145
146 external_delegate_ = external_lib_.create(ckeys.data(), cvalues.data(),
147 ckeys.size(), nullptr);
148 if (external_delegate_) {
149 wrapper_delegate_ = {
150 .data_ = reinterpret_cast<void*>(this),
151 .Prepare = DelegatePrepare,
152 .CopyFromBufferHandle = nullptr,
153 .CopyToBufferHandle = nullptr,
154 .FreeBufferHandle = nullptr,
155 .flags = external_delegate_->flags,
156 };
157 if (external_delegate_->CopyFromBufferHandle) {
158 wrapper_delegate_.CopyFromBufferHandle = DelegateCopyFromBufferHandle;
159 }
160 if (external_delegate_->CopyToBufferHandle) {
161 wrapper_delegate_.CopyToBufferHandle = DelegateCopyToBufferHandle;
162 }
163 if (external_delegate_->FreeBufferHandle) {
164 wrapper_delegate_.FreeBufferHandle = DelegateFreeBufferHandle;
165 }
166 }
167 }
168 }
169
~ExternalDelegateWrapper()170 ExternalDelegateWrapper::~ExternalDelegateWrapper() {
171 if (external_delegate_ != nullptr) {
172 external_lib_.destroy(external_delegate_);
173 }
174 }
175
176 } // namespace
177 } // namespace tflite
178
179 // TfLiteExternalDelegateOptionsInsert adds key/value to the given
180 // TfLiteExternalDelegateOptions instance.
TfLiteExternalDelegateOptionsInsert(TfLiteExternalDelegateOptions * options,const char * key,const char * value)181 TfLiteStatus TfLiteExternalDelegateOptionsInsert(
182 TfLiteExternalDelegateOptions* options, const char* key,
183 const char* value) {
184 if (options->count >= kMaxOptions) {
185 return kTfLiteError;
186 }
187 options->keys[options->count] = key;
188 options->values[options->count] = value;
189 options->count++;
190 return kTfLiteOk;
191 }
192
TfLiteExternalDelegateOptionsDefault(const char * lib_path)193 TfLiteExternalDelegateOptions TfLiteExternalDelegateOptionsDefault(
194 const char* lib_path) {
195 // As 'keys' and 'values' don't need to be set here, using designated
196 // initializers may cause a compiling error as "non-trivial designated
197 // initializers not supported" by some compiler.
198 TfLiteExternalDelegateOptions options;
199 options.lib_path = lib_path;
200 options.count = 0;
201 options.insert = TfLiteExternalDelegateOptionsInsert;
202 return options;
203 }
204
TfLiteExternalDelegateCreate(const TfLiteExternalDelegateOptions * options)205 TfLiteDelegate* TfLiteExternalDelegateCreate(
206 const TfLiteExternalDelegateOptions* options) {
207 auto* external_delegate_wrapper =
208 new tflite::ExternalDelegateWrapper(options);
209 if (external_delegate_wrapper) {
210 return external_delegate_wrapper->tflite_wrapper_delegate();
211 }
212 return nullptr;
213 }
214
TfLiteExternalDelegateDelete(TfLiteDelegate * delegate)215 void TfLiteExternalDelegateDelete(TfLiteDelegate* delegate) {
216 delete tflite::GetExternalDelegateWrapper(delegate);
217 }
218