feat: add android xnnpack delegate - #206
Open
patrickkabwe wants to merge 2 commits into
Open
Conversation
mrousavy
requested changes
Sep 11, 2026
mrousavy
left a comment
Member
There was a problem hiding this comment.
This PR has many code changes that seem unrelated to XNNPACK.
Specifically the change from * to shared_ptr<>.
For stuff like this, please always create atomic PRs - split this change out into a single PR, then add the XNNPACK stacked ontop of it if this really was required to add XNNPACK. If it wasn't required, don't stack.
Individual atomic PRs.
| namespace margelo::nitro::tflite { | ||
|
|
||
| HybridTfliteModel::HybridTfliteModel(TfLiteInterpreter* interpreter, | ||
| HybridTfliteModel::HybridTfliteModel(std::shared_ptr<TfLiteInterpreter> interpreter, |
Comment on lines
-31
to
-38
| HybridTfliteModel::~HybridTfliteModel() { | ||
| if (_interpreter != nullptr) { | ||
| TfLiteInterpreterDelete(_interpreter); | ||
| _interpreter = nullptr; | ||
| } | ||
| // _modelData (shared_ptr<ArrayBuffer>) is automatically freed | ||
| } | ||
|
|
Comment on lines
-20
to
+21
| explicit HybridTfliteModel(TfLiteInterpreter* interpreter, std::shared_ptr<ArrayBuffer> modelData, | ||
| explicit HybridTfliteModel(std::shared_ptr<TfLiteInterpreter> interpreter, | ||
| std::shared_ptr<ArrayBuffer> modelData, |
Comment on lines
-36
to
+87
| TfLiteModel* model = TfLiteModelCreate(modelData->data(), modelData->size()); | ||
| validateDelegateConfiguration(delegates); | ||
|
|
||
| const std::unique_ptr<TfLiteModel, decltype(&TfLiteModelDelete)> model( | ||
| TfLiteModelCreate(modelData->data(), modelData->size()), TfLiteModelDelete); | ||
| if (model == nullptr) { | ||
| throw std::runtime_error("Failed to create TFLite model from data!"); | ||
| } | ||
|
|
||
| // Configure interpreter via options | ||
| TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate(); | ||
| const std::unique_ptr<TfLiteInterpreterOptions, decltype(&TfLiteInterpreterOptionsDelete)> | ||
| options(TfLiteInterpreterOptionsCreate(), TfLiteInterpreterOptionsDelete); | ||
| if (options == nullptr) { | ||
| throw std::runtime_error("TFLite: Failed to create interpreter options!"); | ||
| } | ||
|
|
||
| // Add all hardware accelerated delegates (e.g. GPU, NPU, ...) | ||
| // if any. The default CPU delegate will always be available. | ||
| // Add all requested delegates. The default CPU kernels stay available for | ||
| // operators outside delegated partitions. | ||
| std::vector<std::shared_ptr<TfLiteDelegate>> delegateOwners; | ||
| delegateOwners.reserve(delegates.size()); | ||
| for (const TensorflowModelDelegate& delegateType : delegates) { | ||
| TfLiteDelegate* delegate = getDelegate(delegateType); | ||
| TfLiteInterpreterOptionsAddDelegate(options, delegate); | ||
| std::shared_ptr<TfLiteDelegate> delegate = getDelegate(delegateType); | ||
| TfLiteInterpreterOptionsAddDelegate(options.get(), delegate.get()); | ||
| delegateOwners.push_back(std::move(delegate)); | ||
| } | ||
|
|
||
| TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options); | ||
|
|
||
| // Options and model object can be deleted immediately after interpreter creation. | ||
| // (per TFLite C API docs — the model_data buffer must still outlive the interpreter, | ||
| // which is handled by _modelData shared_ptr in HybridTfliteModel) | ||
| TfLiteInterpreterOptionsDelete(options); | ||
| TfLiteModelDelete(model); | ||
|
|
||
| if (interpreter == nullptr) { | ||
| TfLiteInterpreter* rawInterpreter = TfLiteInterpreterCreate(model.get(), options.get()); | ||
| if (rawInterpreter == nullptr) { | ||
| throw std::runtime_error("Failed to create TFLite interpreter!"); | ||
| } | ||
| const std::shared_ptr<TfLiteInterpreter> interpreter( | ||
| rawInterpreter, | ||
| [modelData, delegateOwners = std::move(delegateOwners)](TfLiteInterpreter* value) { | ||
| (void)modelData; | ||
| (void)delegateOwners; | ||
| TfLiteInterpreterDelete(value); | ||
| }); |
Member
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
XNNPACK is Android-only, cannot be combined with
android-gpuornnapi, and uses an auto-detected thread count capped for mobile devices.Finding that led to the change:
On Samsung SM-G998B / Android 15 with the example Harness benchmark: