2019-04-17 10:49:11 +08:00
|
|
|
//
|
|
|
|
// GLBackend.h
|
|
|
|
// MNN
|
|
|
|
//
|
|
|
|
// Created by MNN on 2019/01/31.
|
|
|
|
// Copyright © 2018, Alibaba Group Holding Limited
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef GLBACKEND_H
|
|
|
|
#define GLBACKEND_H
|
|
|
|
|
|
|
|
#include <list>
|
|
|
|
#include <map>
|
|
|
|
#include <memory>
|
2019-12-27 22:16:57 +08:00
|
|
|
#include "core/Backend.hpp"
|
|
|
|
#include "backend/opengl/GLContext.hpp"
|
|
|
|
#include "backend/opengl/GLProgram.hpp"
|
|
|
|
#include "backend/opengl/GLSSBOBuffer.hpp"
|
|
|
|
#include "backend/opengl/GLTexture.hpp"
|
2019-05-24 11:26:54 +08:00
|
|
|
#include "MNN_generated.h"
|
2019-12-27 22:16:57 +08:00
|
|
|
#include "backend/opengl/GLUtils.hpp"
|
|
|
|
#include "core/TensorUtils.hpp"
|
|
|
|
#include "backend/opengl/GLHead.hpp"
|
2019-04-17 10:49:11 +08:00
|
|
|
|
|
|
|
namespace MNN {
|
2019-05-24 11:26:54 +08:00
|
|
|
namespace OpenGL {
|
2019-04-17 10:49:11 +08:00
|
|
|
class GLBackend : public Backend {
|
|
|
|
public:
|
- dynamic computation graph (beta)
- add supports (/express)
- add tests
- add benchmarks with it (/benchmark/exprModels)
- Python
- MNN engine and tools were submitted to pip
- available on Windows/macOS/Linux
- Engine/Converter
- add supports for each op benchmarking
- refactor optimizer by separating steps
- CPU
- add supports for Conv3D, Pool3D, ELU, ReverseSequence
- fix ArgMax, Permute, Scale, BinaryOp, Slice, SliceTf
- OpenCL
- add half transform in CPU
- add broadcast supports for binary
- optimize Conv2D, Reshape, Eltwise, Gemm, etc.
- OpenGL
- add sub, real div supports for binary
- add supports for unary
- optimize Conv2D, Reshape
- Vulkan
- add max supports for eltwise
- Metal
- fix metallib missing problem
- Train/Quantization
- use express to refactor training codes
2019-09-26 21:02:07 +08:00
|
|
|
GLBackend(BackendConfig::PrecisionMode precision, BackendConfig::PowerMode power);
|
2019-04-17 10:49:11 +08:00
|
|
|
virtual ~GLBackend();
|
|
|
|
|
|
|
|
void upload(GLuint textureId, const float* inputData, int d1, int d2, int d3, bool align = false) const;
|
|
|
|
void download(GLuint textureId, float* outputData, int d1, int d2, int d3, bool align = false) const;
|
|
|
|
|
2019-07-02 18:01:08 +08:00
|
|
|
void copyImageToNhwcBuffer(GLuint textureId, float *outputData, int width, int height, int channel) const;
|
|
|
|
void copyNhwcBufferToImage(GLuint textureId, const float *inputData, int width, int height, int channel) const;
|
2019-12-27 22:16:57 +08:00
|
|
|
|
2019-04-17 10:49:11 +08:00
|
|
|
std::shared_ptr<GLProgram> getProgram(const std::string& key, const char* content);
|
|
|
|
std::shared_ptr<GLProgram> getProgram(const std::string& key, const char* content,
|
|
|
|
const std::vector<std::string>& prefix);
|
2019-12-27 22:16:57 +08:00
|
|
|
|
2019-06-24 11:32:41 +08:00
|
|
|
enum GPUType { ADRENO = 0, MALI = 1, OTHER = 2 };
|
2019-04-17 10:49:11 +08:00
|
|
|
|
2019-06-24 11:32:41 +08:00
|
|
|
inline GPUType gpuType() const {
|
|
|
|
return mGpuType;
|
|
|
|
}
|
2019-12-27 22:16:57 +08:00
|
|
|
|
2019-06-24 11:32:41 +08:00
|
|
|
inline int glVersion() const {
|
|
|
|
return mVersion;
|
|
|
|
}
|
2019-12-27 22:16:57 +08:00
|
|
|
|
2019-07-02 18:01:08 +08:00
|
|
|
void wait() const;
|
2019-12-27 22:16:57 +08:00
|
|
|
|
2019-07-02 18:01:08 +08:00
|
|
|
void compute(int dim1, int dim2, int dim3, bool needWait = false) const;
|
|
|
|
|
2019-04-17 10:49:11 +08:00
|
|
|
/*For Buffer alloc and release*/
|
|
|
|
virtual bool onAcquireBuffer(const Tensor* nativeTensor, StorageType storageType) override;
|
|
|
|
|
|
|
|
// If STATIC, delete the buffer. If dynamic don't free the buffer, just set it to reused
|
|
|
|
virtual bool onReleaseBuffer(const Tensor* nativeTensor, StorageType storageType) override;
|
|
|
|
|
|
|
|
// Clear All Dynamic Buffer
|
|
|
|
virtual bool onClearBuffer() override;
|
|
|
|
|
|
|
|
virtual void onCopyBuffer(const Tensor* srcTensor, const Tensor* dstTensor) const override;
|
|
|
|
|
|
|
|
virtual void onExecuteBegin() const override;
|
|
|
|
|
|
|
|
virtual void onExecuteEnd() const override;
|
|
|
|
|
|
|
|
/// get execution
|
|
|
|
virtual Execution* onCreate(const std::vector<Tensor*>& inputs, const std::vector<Tensor*>& outputs,
|
|
|
|
const MNN::Op* op) override;
|
|
|
|
|
2019-05-24 11:26:54 +08:00
|
|
|
class Creator {
|
|
|
|
public:
|
|
|
|
virtual ~Creator() = default;
|
|
|
|
virtual Execution *onCreate(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &output, const MNN::Op *op, Backend *backend) const = 0;
|
|
|
|
};
|
2019-07-02 18:01:08 +08:00
|
|
|
static bool addCreator(OpType t, Creator *c);
|
2019-07-25 13:36:35 +08:00
|
|
|
bool isCreateError() const;
|
|
|
|
bool isSupportHalf() const;
|
|
|
|
bool getOpenGLExtensions(std::string extStr);
|
|
|
|
GLenum getTextrueFormat() const;
|
|
|
|
std::string getImageFormat() const;
|
|
|
|
std::shared_ptr<GLProgram> getTreatedProgramWithPrefix(const char *content,
|
|
|
|
const std::vector<std::string> &prefix);
|
|
|
|
std::shared_ptr<GLProgram> getTreatedProgram(const char *content);
|
2019-04-17 10:49:11 +08:00
|
|
|
private:
|
|
|
|
struct Runtime {
|
2019-07-02 18:01:08 +08:00
|
|
|
std::shared_ptr<GLProgram> mNchw2ImageProgram;
|
|
|
|
std::shared_ptr<GLProgram> mImage2NchwProgram;
|
|
|
|
std::shared_ptr<GLProgram> mNc4hw42ImageProgram;
|
|
|
|
std::shared_ptr<GLProgram> mImage2Nc4hw4Program;
|
2019-12-27 22:16:57 +08:00
|
|
|
|
2019-07-02 18:01:08 +08:00
|
|
|
std::shared_ptr<GLProgram> mNhwc2ImageProgram;
|
|
|
|
std::shared_ptr<GLProgram> mImage2NhwcProgram;
|
2019-04-17 10:49:11 +08:00
|
|
|
|
|
|
|
std::map<std::string, std::shared_ptr<GLProgram>> mProgramCache;
|
|
|
|
|
|
|
|
std::list<std::shared_ptr<GLTexture>> mBlocks;
|
|
|
|
std::list<std::pair<const Tensor*, GLuint>> mFreeTextures;
|
|
|
|
mutable std::shared_ptr<GLSSBOBuffer> mTempBuffer;
|
|
|
|
};
|
2019-07-25 13:36:35 +08:00
|
|
|
Runtime* mRuntime = nullptr;
|
|
|
|
static std::unique_ptr<GLContext> mContext;
|
2019-06-24 11:32:41 +08:00
|
|
|
GPUType mGpuType = OTHER;
|
|
|
|
int mVersion = 0;
|
2019-07-02 18:01:08 +08:00
|
|
|
int mLocalSize[3];
|
2019-12-27 22:16:57 +08:00
|
|
|
bool mIsCreateError{false};
|
2019-07-25 13:36:35 +08:00
|
|
|
bool mIsSupportHalf{false};
|
|
|
|
GLenum mTextrueFormat{GL_RGBA32F};
|
|
|
|
std::string mImageFormat{"rgba32f"};
|
2019-05-24 11:26:54 +08:00
|
|
|
};
|
|
|
|
|
2019-07-02 18:01:08 +08:00
|
|
|
inline std::vector<int> tensorShapeFormat(const Tensor *input) {
|
|
|
|
int iN = std::max(1, input->batch());
|
|
|
|
int iC = std::max(1, input->channel());
|
|
|
|
int iH = std::max(1, input->height());
|
|
|
|
int iW = std::max(1, input->width());
|
2019-12-27 22:16:57 +08:00
|
|
|
|
2019-07-02 18:01:08 +08:00
|
|
|
if (input->dimensions() == 3) {
|
|
|
|
iN = 1;
|
|
|
|
iH = input->buffer().dim[0].extent;
|
|
|
|
iW = input->buffer().dim[1].extent;
|
|
|
|
iC = input->buffer().dim[2].extent;
|
|
|
|
}
|
2019-12-27 22:16:57 +08:00
|
|
|
|
2019-07-02 18:01:08 +08:00
|
|
|
if (input->dimensions() == 2) {
|
|
|
|
iN = input->buffer().dim[0].extent;
|
|
|
|
iH = 1;
|
|
|
|
iW = 1;
|
|
|
|
iC = input->buffer().dim[1].extent;
|
|
|
|
}
|
|
|
|
if (input->dimensions() == 1) {
|
|
|
|
iN = 1;
|
|
|
|
iH = 1;
|
|
|
|
iW = 1;
|
|
|
|
iC = input->buffer().dim[0].extent;
|
|
|
|
}
|
2019-12-27 22:16:57 +08:00
|
|
|
|
2019-07-02 18:01:08 +08:00
|
|
|
#ifdef LOG_VERBOSE
|
|
|
|
MNN_PRINT("dim %d : [%d, %d, %d, %d] \n",input->dimensions(), iN, iH, iW, iC);
|
|
|
|
#endif
|
|
|
|
std::vector<int> shape_vec{iN, iH, iW, iC};
|
2019-12-27 22:16:57 +08:00
|
|
|
|
2019-07-02 18:01:08 +08:00
|
|
|
return shape_vec;
|
|
|
|
}
|
2019-12-27 22:16:57 +08:00
|
|
|
|
2019-05-24 11:26:54 +08:00
|
|
|
template <class T>
|
|
|
|
class GLCreatorRegister {
|
|
|
|
public:
|
|
|
|
GLCreatorRegister(OpType type) {
|
2019-07-02 18:01:08 +08:00
|
|
|
GLBackend::addCreator(type, new T);
|
2019-05-24 11:26:54 +08:00
|
|
|
}
|
|
|
|
~GLCreatorRegister() = default;
|
2019-04-17 10:49:11 +08:00
|
|
|
};
|
2019-05-24 11:26:54 +08:00
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class TypedCreator : public GLBackend::Creator {
|
|
|
|
public:
|
|
|
|
virtual ~TypedCreator() = default;
|
|
|
|
virtual Execution *onCreate(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs, const MNN::Op *op,
|
|
|
|
Backend *backend) const override {
|
|
|
|
return new T(inputs, op, backend);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace OpenGL
|
2019-04-17 10:49:11 +08:00
|
|
|
} // namespace MNN
|
|
|
|
#endif
|