blob: e99e324745a970362801d48bc4a5aac4bdc60b0f [file] [edit]
/*
* Copyright (C) 2021 MediaTek Inc., this file is modified on 02/26/2021
* by MediaTek Inc. based on MIT License .
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the ""Software""), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef DELEGATE_MTK_NEURON_NEURON_DELEGATE_KERNEL_H_
#define DELEGATE_MTK_NEURON_NEURON_DELEGATE_KERNEL_H_
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "common/simple_async_delegate.h"
#include "delegate/mtk_neuron/neuron_async_kernel.h"
#include "delegate/mtk_neuron/neuron_delegate.h"
#include "delegate/mtk_neuron/neuron_delegate_builder.h"
#include "delegate/mtk_neuron/neuron_implementation.h"
#include "tensorflow/lite/c/c_api_opaque.h"
#include "tensorflow/lite/core/async/c/task.h"
#include "tensorflow/lite/delegates/utils/simple_opaque_delegate.h"
#define NEURON_REUSABLE_EXECUTION
namespace tflite {
namespace neuron {
class DelegateAsyncKernel;
// The kernel that represents the node sub set of TFLite being run on Neuron
// API.
struct NeuronOpMappingArgs {
TfLiteOpaqueContext* context;
NeuronOpBuilder* builder;
TfLiteOpaqueNode* node;
std::vector<int>* model_state_outputs;
std::vector<int>* model_state_tfl_inputs;
std::vector<std::tuple<int, int>>* feedback_loops;
/// M: NeuroPilot {@
TfLiteRegistrationExternal* registration;
/// M: NeuroPilot @}
int* neuron_errno;
};
// Manage Neuron shared memory handle
class NNMemory {
public:
NNMemory(const NeuronApi* neuronapi, const char* name, size_t size,
bool use_ahwb, bool use_cacheable_buffer);
~NNMemory();
uint8_t* get_data_ptr() { return data_ptr_; }
NeuronMemory* get_handle() { return nn_memory_handle_; }
size_t get_byte_size() { return byte_size_; }
int ion_memory_lock() {
#if defined(__ANDROID__)
if (buffer_) {
return AHardwareBuffer_lock(buffer_,
AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
-1, NULL,
reinterpret_cast<void**>(&data_ptr_));
}
#endif
return 0;
}
int ion_memory_unlock() {
#if defined(__ANDROID__)
if (buffer_) {
return AHardwareBuffer_unlock(buffer_, nullptr);
}
#endif
return 0;
}
private:
// NeuronApi instance to use. Not owned by this object.
const NeuronApi* neuronapi_;
int fd_ = -1;
size_t byte_size_ = 0;
uint8_t* data_ptr_ = nullptr;
bool use_ahwb_ = false;
NeuronMemory* nn_memory_handle_ = nullptr;
#if defined(__ANDROID__)
AHardwareBuffer* buffer_ = nullptr;
#else
int dma_heap_fd_ = 0;
#endif
};
// RAII Neuron Model Destructor for use with std::unique_ptr
class NNFreeModel {
public:
explicit NNFreeModel(const NeuronApi* neuronapi) : neuronapi_(neuronapi) {}
void operator()(NeuronModel* model) { neuronapi_->NeuronModel_free(model); }
private:
// NeuronApi instance to use. Not owned by this object.
const NeuronApi* neuronapi_;
};
// RAII Neuron Compilation Destructor for use with std::unique_ptr
class NNFreeCompilation {
public:
explicit NNFreeCompilation(const NeuronApi* neuronapi)
: neuronapi_(neuronapi) {}
void operator()(NeuronCompilation* compilation) {
neuronapi_->NeuronCompilation_free(compilation);
}
private:
// NeuronApi instance to use. Not owned by this object.
const NeuronApi* neuronapi_;
};
// RAII Neuron Execution Destructor for use with std::unique_ptr
class NNFreeExecution {
public:
explicit NNFreeExecution(const NeuronApi* neuronapi)
: neuronapi_(neuronapi) {}
void operator()(NeuronExecution* execution) {
neuronapi_->NeuronExecution_free(execution);
}
private:
// NeuronApi instance to use. Not owned by this object.
const NeuronApi* neuronapi_;
};
// TODO(Code): Mode NNCompilationArgs to another Util file.
class NNCompilationArgs {
public:
static const std::string& GetArgs(ExecutionPreference preference) {
#ifdef MTK_GITHUB_RELEASE
static const std::string kFastSingleAnswerArgs = "--opt 3";
#else
static const std::string kFastSingleAnswerArgs = "--opt-accuracy --opt 3";
#endif
return kFastSingleAnswerArgs;
}
};
enum DelegateSpecificMode {
// Normal Mode, get information from context
kNormalMode = 0,
// Get model information from one_node_and_reg_
// Currently only for getSupportedForOneNode
kOneNodeMode = 1,
kSubgraphMode = 2,
kContextMode = 3,
};
// Neuron delegate kernel.
class NeuronStableDelegateKernel
: public cros::SimpleAsyncDelegateKernelInterface {
public:
static TfLiteStatus Map(TfLiteOpaqueContext* context, int builtin_code,
int version, int neuron_platform_version,
const NeuronOpMappingArgs& mapping_args,
NeuronOperationType* nn_op_type);
NeuronStableDelegateKernel();
explicit NeuronStableDelegateKernel(const NeuronApi* neuronapi,
const NeuronDelegateOptions& options)
: async_kernel_(std::make_unique<DelegateAsyncKernel>(this)),
neuronapi_(neuronapi),
options_(options),
nn_model_(nullptr, NNFreeModel(neuronapi_)),
nn_compilation_(nullptr, NNFreeCompilation(neuronapi_)),
#ifdef NEURON_REUSABLE_EXECUTION
nn_execution_(nullptr, NNFreeExecution(neuronapi_))
#endif
{
}
virtual ~NeuronStableDelegateKernel() = default;
TfLiteStatus Init(TfLiteOpaqueContext* context,
const TfLiteOpaqueDelegateParams* params) override;
TfLiteStatus Prepare(TfLiteOpaqueContext* context,
TfLiteOpaqueNode* node) override;
TfLiteStatus Eval(TfLiteOpaqueContext* context,
TfLiteOpaqueNode* node) override;
TfLiteStatus Eval(TfLiteOpaqueContext* context, TfLiteOpaqueNode* node,
TfLiteExecutionTask* task);
TfLiteAsyncKernel* AsyncKernel(TfLiteOpaqueContext* context,
TfLiteOpaqueNode* node) override;
TfLiteStatus GetSupportedOperationsForOneNode(
TfLiteOpaqueContext* context, TfLiteOpaqueNode* node,
TfLiteRegistrationExternal* registration, bool* is_supported);
TfLiteStatus GetSupportedOperationsForWholeGraph(TfLiteOpaqueContext* context,
bool* is_supported);
TfLiteStatus GetSupportedOperations(TfLiteOpaqueContext* context,
const TfLiteIntArray* input_tensors,
const TfLiteIntArray* output_tensors,
bool* is_supported);
TfLiteStatus RegisterBuffer(TfLiteBufferHandle buf_handle, int buf_fd,
size_t buf_size);
TfLiteStatus UnregisterBuffer(TfLiteBufferHandle buf_handle);
private:
std::unique_ptr<DelegateAsyncKernel> async_kernel_;
const NeuronApi* neuronapi_;
NeuronDelegateOptions options_;
// True if initialization has been completed successfully
bool initialised_;
std::unique_ptr<NeuronModel, NNFreeModel> nn_model_;
std::unique_ptr<NeuronCompilation, NNFreeCompilation> nn_compilation_;
#ifdef NEURON_REUSABLE_EXECUTION
std::unique_ptr<NeuronExecution, NNFreeExecution> nn_execution_;
#endif
// Node indices that this delegate is responsible for. Indices here
// indexes into the nodes array in the TfLiteContext.
std::vector<int> nodes_;
// Track indices we use
OperandMapping operand_mapping_;
std::map<TfLiteBufferHandle, NeuronMemory*> tensor_memory_map_kernel_;
std::vector<int> model_state_outputs_;
std::vector<int> model_state_tfl_inputs_;
// This is the equivalent of the pair model_state_outputs_,
// model_state_tfl_inputs_ for all tensors where we have to keep the output
// data available for TFLite model users
std::vector<std::tuple<int, int>> feedback_loops_;
std::unique_ptr<NNMemory> nn_input_memory_;
std::unique_ptr<NNMemory> nn_output_memory_;
std::vector<uint8_t> nn_compilation_cache_token_;
// Prevent set memory multi-times when we use ahwb
bool need_set_memory_ = true;
// Number of the ops in NeuronModel
int total_op_num_ = 0;
// Neuron delegate specific run mode
DelegateSpecificMode delegate_specific_mode_ = kNormalMode;
// For One Node Mode
std::pair<TfLiteOpaqueNode*, TfLiteRegistrationExternal*> one_node_and_reg_ =
{nullptr, nullptr};
void AddDequantizeOperatorsWhereNeeded(const TfLiteOpaqueContext* context,
int builtin_code,
const TfLiteOpaqueNode* node,
NeuronOpBuilder* builder);
TfLiteStatus AddOpsAndTensors(TfLiteOpaqueContext* context);
TfLiteStatus BuildGraph(TfLiteOpaqueContext* context,
const TfLiteOpaqueDelegateParams* params,
const TfLiteIntArray* input_tensors,
const TfLiteIntArray* output_tensors);
};
} // namespace neuron
} // namespace tflite
#endif // DELEGATE_MTK_NEURON_NEURON_DELEGATE_KERNEL_H_