/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_PACKAGES_MODULES_NEURALNETWORKS_RUNTIME_OPERATION_CONVERTERS_SUBGRAPH_CONTEXT_H #define ANDROID_PACKAGES_MODULES_NEURALNETWORKS_RUNTIME_OPERATION_CONVERTERS_SUBGRAPH_CONTEXT_H #include #include #include "FlatbufferModelBuilderUtils.h" #include "NeuralNetworks.h" namespace android { namespace nn { // This keeps track of all the data needed to convert NNAPI subgraphs to TFLite subgraphs // This also provides information needed to convert NNAPI Operations to TFLite Operators // Once the subgraph is done building, call finish() to return the flatbuffer class SubGraphContext { public: SubGraphContext(const Model* model, const Model::Subgraph* subgraph, flatbuffers::FlatBufferBuilder* builder, std::vector* opCodesVector, std::vector* opCodeIndexForOperationType, std::vector* bufferVector); SubGraphFlatbuffer finish(); // If the operandIdx is -1, it suggests that the tensor being added doesn't have a // corresponding Operand from the NNAPI NDK model. // Returns index of Tensor being added. int addTensorFlatbuffer(TensorFlatbuffer tensor, int32_t operandIdx = -1); void addOperatorFlatbuffer(OperatorFlatbuffer opFlatbuffer); void addSubGraphInput(int32_t operandIdx); void addSubGraphOutput(int32_t operandIdx); const Model::Subgraph* getSubgraph() const { return mSubgraph; } // Returns -1 if there is no corresponding tensor index int getTensorIdxFromOperandIdx(int operandIdx) const; uint32_t addOpCode(OperationType operationType); flatbuffers::FlatBufferBuilder& getBuilder() { return *mBuilder; } // OperandLifeTime must be CONSTANT_COPY or CONSTANT_REFERENCE // Will crash if OperandLifeTime is not either of the two. // dataSize is the size of data in bytes. template void copyConstantValueToData(const Operand& operand, Type* data, size_t dataSize); template Type getConstantScalar(const Operand& operand); // Returns Buffer index uint32_t addBufferFromData(const uint8_t* data, uint32_t length); // makeSymmetric turns asymmetric tensors to symmetric by doing setting data = data - zeroPoint // makeSymmetric is supported only for constant OperandType::TENSOR_QUANT8_ASYMM_SIGNED // If unsupported type is passed, makeSymmetric is ignored Result createTensorFlatbufferFromOperand(uint32_t operandIdx, bool makeSymmetric = false); private: const Mapping& getMapping(uint32_t poolIndex); std::pair getConstantPointerAndLength(const Operand& operand); const Model* mModel; const Model::Subgraph* mSubgraph; flatbuffers::FlatBufferBuilder* mBuilder; std::vector* mOpCodesVector; std::vector* mOpCodeIndexForOperationType; std::vector* mBufferVector; std::vector mOperatorVector; std::vector mTensorVector; std::vector mInputTensors; std::vector mOutputTensors; std::vector mOperandToTensorIdx; // Each index corresponds to the pool index of shared memory std::vector mMappings; }; template void SubGraphContext::copyConstantValueToData(const Operand& operand, Type* data, size_t dataSize) { auto [pointer, length] = getConstantPointerAndLength(operand); CHECK_GE(dataSize, length); std::memcpy(data, pointer, length); } template Type SubGraphContext::getConstantScalar(const Operand& operand) { Type data; copyConstantValueToData(operand, &data, sizeof(Type)); return data; } } // namespace nn } // namespace android #endif // ANDROID_PACKAGES_MODULES_NEURALNETWORKS_RUNTIME_OPERATION_CONVERTERS_SUBGRAPH_CONTEXT_H