| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | //  GLBackend.cpp
 | 
					
						
							|  |  |  | //  MNN
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //  Created by MNN on 2019/01/31.
 | 
					
						
							|  |  |  | //  Copyright © 2018, Alibaba Group Holding Limited
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <sstream>
 | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  | #include "AllShader.hpp"
 | 
					
						
							|  |  |  | #include "GLSSBOBuffer.hpp"
 | 
					
						
							|  |  |  | #include "GLTexture.hpp"
 | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | #include <MNN/AutoTime.hpp>
 | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  | #include "GLBackend.hpp"
 | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | #include "core/Macro.h"
 | 
					
						
							|  |  |  | #include "core/TensorUtils.hpp"
 | 
					
						
							| 
									
										
										
										
											2023-09-04 10:42:11 +08:00
										 |  |  | #include "core/BufferAllocator.hpp"
 | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  | #include <mutex>
 | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | #include <MNN/Tensor.hpp>
 | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  | std::map<OpType, GLBackend::Creator*>* gCreator() { | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  |     static std::once_flag once; | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     static std::map<OpType, GLBackend::Creator*>* creators = nullptr; | 
					
						
							|  |  |  |     std::call_once(once, [&]() { creators = new std::map<OpType, GLBackend::Creator*>; }); | 
					
						
							|  |  |  |     return creators; | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  | bool GLBackend::addCreator(OpType t, Creator* c) { | 
					
						
							|  |  |  |     auto map = gCreator(); | 
					
						
							|  |  |  |     if (map->find(t) != map->end()) { | 
					
						
							|  |  |  |         MNN_PRINT("Error: %d type has be added\n", t); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     map->insert(std::make_pair(t, c)); | 
					
						
							|  |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  | std::shared_ptr<GLProgram> GLBackend::getTreatedProgramWithPrefix(const char *content, const std::vector<std::string> &prefix) { | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     std::ostringstream tc; | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |     tc << GLProgram::getHead(getImageFormat()); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     for (auto &s : prefix) { | 
					
						
							|  |  |  |         tc << s << "\n"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     tc << content; | 
					
						
							|  |  |  |     return std::shared_ptr<GLProgram>(new GLProgram(tc.str())); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | std::shared_ptr<GLProgram> GLBackend::getTreatedProgram(const char *content) { | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     std::ostringstream tc; | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |     tc << GLProgram::getHead(getImageFormat()) << content; | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     return std::shared_ptr<GLProgram>(new GLProgram(tc.str())); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  | bool GLBackend::getOpenGLExtensions(const std::string& extStr) { | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |     const std::string extension_str((const char*)glGetString(GL_EXTENSIONS)); | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  |     return extension_str.find(extStr.c_str()) != std::string::npos; | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool GLBackend::isSupportHalf() const{ | 
					
						
							|  |  |  |     return mIsSupportHalf; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GLenum GLBackend::getTextrueFormat() const{ | 
					
						
							|  |  |  |     return mTextrueFormat; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  | std::string GLBackend::getImageFormat() const{ | 
					
						
							|  |  |  |     return mImageFormat; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::unique_ptr<GLContext> GLBackend::mContext = nullptr; | 
					
						
							| 
									
										
										
											
												- 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::GLBackend(BackendConfig::PrecisionMode precision, BackendConfig::PowerMode power) : Backend(MNN_FORWARD_OPENGL) { | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |     if (mContext == nullptr) { | 
					
						
							|  |  |  |         mContext.reset(new GLContext()); | 
					
						
							|  |  |  |         if(mContext != nullptr){ | 
					
						
							|  |  |  |             if(mContext->isCreateError()){ | 
					
						
							|  |  |  |                 MNN_PRINT("mContext error !!! \n"); | 
					
						
							|  |  |  |                 mIsCreateError = true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }else{ | 
					
						
							|  |  |  |             MNN_PRINT("mContext == nullptr !!! \n"); | 
					
						
							|  |  |  |             mIsCreateError = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     mIsSupportHalf = getOpenGLExtensions("GL_EXT_color_buffer_half_float"); | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  |     if(mIsSupportHalf && precision != BackendConfig::Precision_High) { | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |         mTextrueFormat = GL_RGBA16F; | 
					
						
							|  |  |  |         mImageFormat = "rgba16f"; | 
					
						
							|  |  |  |     }else{ | 
					
						
							|  |  |  |         MNN_PRINT("not support half \n"); | 
					
						
							|  |  |  |         mTextrueFormat = GL_RGBA32F; | 
					
						
							|  |  |  |         mImageFormat = "rgba32f"; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  |     mRuntime                       = new Runtime; | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     mRuntime->mImage2NchwProgram     = getTreatedProgram(glsl_image_to_nchw_buffer_glsl); | 
					
						
							|  |  |  |     mRuntime->mNchw2ImageProgram       = getTreatedProgram(glsl_nchw_buffer_to_image_glsl); | 
					
						
							|  |  |  |     mRuntime->mNc4hw42ImageProgram   = getTreatedProgram(glsl_nc4hw4_buffer_to_image_glsl); | 
					
						
							|  |  |  |     mRuntime->mImage2Nc4hw4Program = getTreatedProgram(glsl_image_to_nc4hw4_buffer_glsl); | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     std::vector<std::string> prefix; | 
					
						
							|  |  |  |     setLocalSize(prefix, mLocalSize, 8, 8, 1); | 
					
						
							|  |  |  |     mRuntime->mNhwc2ImageProgram   = getProgram("nhwc_buffer_to_image", glsl_nhwc_buffer_to_image_glsl, prefix); | 
					
						
							|  |  |  |     mRuntime->mImage2NhwcProgram = getProgram("image_to_nhwc_buffer", glsl_image_to_nhwc_buffer_glsl, prefix); | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  |     const GLubyte* renderer = glGetString(GL_RENDERER); | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     if(renderer != nullptr){ | 
					
						
							|  |  |  |         MNN_PRINT("gpu type : %s \n", (char*)renderer); | 
					
						
							|  |  |  |         if(strstr((char *) renderer, "Adreno")){ | 
					
						
							|  |  |  |             mGpuType = ADRENO; | 
					
						
							|  |  |  |         }else if(strstr((char *) renderer, "Mali")){ | 
					
						
							|  |  |  |             mGpuType = MALI; | 
					
						
							|  |  |  |         }else{ | 
					
						
							|  |  |  |             mGpuType = OTHER; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  |     const GLubyte* version = glGetString(GL_VERSION); | 
					
						
							|  |  |  |     if(version != nullptr){ | 
					
						
							|  |  |  |         MNN_PRINT("gl version : %s \n", version); | 
					
						
							|  |  |  |         char* p = strstr((char *) version, "V@"); | 
					
						
							|  |  |  |         if(p != nullptr){ | 
					
						
							|  |  |  |             p += strlen("V@"); | 
					
						
							|  |  |  |             char* v = strtok(p, "."); | 
					
						
							|  |  |  |             if(v != nullptr){ | 
					
						
							|  |  |  |                 mVersion = atoi(v); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GLBackend::~GLBackend() { | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     if(mRuntime != nullptr){ | 
					
						
							|  |  |  |         delete mRuntime; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |     if(mContext != nullptr){ | 
					
						
							|  |  |  |         mContext.reset(nullptr); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  | void GLBackend::copyImageToNhwcBuffer(GLuint textureId, float *outputData, int width, int height, int channel) const { | 
					
						
							|  |  |  |     width = std::max(1, width); | 
					
						
							|  |  |  |     height = std::max(1, height); | 
					
						
							|  |  |  |     channel = std::max(1, channel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     wait(); | 
					
						
							|  |  |  |     auto depthQuad = UP_DIV(channel, 4); | 
					
						
							|  |  |  |     auto size      = depthQuad * 4 * width * height * sizeof(float); | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     auto buffer = std::shared_ptr<GLSSBOBuffer>(new GLSSBOBuffer(size)); | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     mRuntime->mImage2NhwcProgram->useProgram(); | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |     glBindImageTexture(0, textureId, 0, GL_TRUE, 0, GL_READ_ONLY, getTextrueFormat()); | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							|  |  |  |     glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, buffer->getId()); | 
					
						
							|  |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     glUniform1i(2, width); | 
					
						
							|  |  |  |     glUniform1i(3, height); | 
					
						
							|  |  |  |     glUniform1i(4, channel); | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     compute(UP_DIV(width, mLocalSize[0]), UP_DIV(height, mLocalSize[1]), UP_DIV(depthQuad, mLocalSize[2])); | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  |     glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); | 
					
						
							|  |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  |     auto gpuoutput = buffer->map(GL_MAP_READ_BIT); | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     if(gpuoutput != nullptr){ | 
					
						
							|  |  |  |         ::memcpy(outputData, gpuoutput, height * width * channel * sizeof(float)); | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     buffer->unmap(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  | void GLBackend::copyNhwcBufferToImage(GLuint textureId, const float *inputData, int width, int height, int channel) const { | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     int c_4 = UP_DIV(channel, 4); | 
					
						
							|  |  |  |     auto size      = ROUND_UP(channel, 4) * width * height * sizeof(float); | 
					
						
							|  |  |  |     auto buffer = std::shared_ptr<GLSSBOBuffer>(new GLSSBOBuffer(size)); | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     auto gpuoutput = buffer->map(GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); | 
					
						
							|  |  |  |     if(gpuoutput != nullptr){ | 
					
						
							|  |  |  |         ::memcpy(gpuoutput, inputData, channel*height*width * sizeof(float)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     buffer->unmap(); | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     mRuntime->mNhwc2ImageProgram->useProgram(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |     glBindImageTexture(0, textureId, 0, GL_TRUE, 0, GL_WRITE_ONLY, getTextrueFormat()); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, buffer->getId()); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     glUniform1i(2, width); | 
					
						
							|  |  |  |     glUniform1i(3, height); | 
					
						
							|  |  |  |     glUniform1i(4, channel); | 
					
						
							|  |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							|  |  |  |     compute(UP_DIV(width, mLocalSize[0]), UP_DIV(height, mLocalSize[1]), UP_DIV(c_4, mLocalSize[2])); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     void GLBackend::wait() const { | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  | #ifdef USE_GL_FINISH
 | 
					
						
							|  |  |  |         glFinish(); | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |         glFlush(); | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  | void GLBackend::compute(int dim1, int dim2, int dim3, bool needWait) const { | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |     wait(); | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     glDispatchCompute(dim1, dim2, dim3); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  | void GLBackend::download(GLuint textureId, float *outputData, int d1, int d2, int d3, bool align) const { | 
					
						
							|  |  |  |     wait(); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     auto depthQuad = UP_DIV(d3, 4); | 
					
						
							|  |  |  |     auto size      = depthQuad * 4 * d1 * d2 * sizeof(float); | 
					
						
							|  |  |  |     if (NULL == mRuntime->mTempBuffer.get() || mRuntime->mTempBuffer->size() < size) { | 
					
						
							|  |  |  |         mRuntime->mTempBuffer = std::shared_ptr<GLSSBOBuffer>(new GLSSBOBuffer(size)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     auto &buffer = mRuntime->mTempBuffer; | 
					
						
							|  |  |  |     if (align) { | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |         mRuntime->mImage2Nc4hw4Program->useProgram(); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |         mRuntime->mImage2NchwProgram->useProgram(); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |     glBindImageTexture(0, textureId, 0, GL_TRUE, 0, GL_READ_ONLY, getTextrueFormat()); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							|  |  |  |     glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, buffer->getId()); | 
					
						
							|  |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							|  |  |  |     glUniform1i(2, d1); | 
					
						
							|  |  |  |     glUniform1i(3, d2); | 
					
						
							|  |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     compute(UP_DIV(d1, 8), UP_DIV(d2, 8), depthQuad); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); | 
					
						
							|  |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto gpuoutput = buffer->map(GL_MAP_READ_BIT); | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     if(gpuoutput != nullptr){ | 
					
						
							|  |  |  |         if (align) { | 
					
						
							|  |  |  |             ::memcpy(outputData, gpuoutput, size); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             ::memcpy(outputData, gpuoutput, d1 * d2 * d3 * sizeof(float)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     buffer->unmap(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  | void GLBackend::upload(GLuint textureId, const float *inputData, int width, int height, int channel, bool align) const { | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     int c_4 = UP_DIV(channel, 4); | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  |     auto size      = ROUND_UP(channel, 4) * width * height * sizeof(float); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     if (NULL == mRuntime->mTempBuffer.get() || mRuntime->mTempBuffer->size() < size) { | 
					
						
							|  |  |  |         mRuntime->mTempBuffer = std::shared_ptr<GLSSBOBuffer>(new GLSSBOBuffer(size)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     auto &buffer = mRuntime->mTempBuffer; | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     auto gpuoutput = buffer->map(GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     if(gpuoutput != nullptr){ | 
					
						
							|  |  |  |         if (align) { | 
					
						
							|  |  |  |             ::memcpy(gpuoutput, inputData, size); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             ::memcpy(gpuoutput, inputData, channel*height*width * sizeof(float)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     buffer->unmap(); | 
					
						
							|  |  |  |     if (align) { | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |         mRuntime->mNc4hw42ImageProgram->useProgram(); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |         mRuntime->mNchw2ImageProgram->useProgram(); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |     glBindImageTexture(0, textureId, 0, GL_TRUE, 0, GL_WRITE_ONLY, getTextrueFormat()); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							|  |  |  |     glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, buffer->getId()); | 
					
						
							|  |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							| 
									
										
										
										
											2019-06-24 11:32:41 +08:00
										 |  |  |     glUniform1i(2, width); | 
					
						
							|  |  |  |     glUniform1i(3, height); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     compute(UP_DIV(width, 8), UP_DIV(height, 8), c_4); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     OPENGL_CHECK_ERROR; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Execution *GLBackend::onCreate(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs, | 
					
						
							|  |  |  |                                const MNN::Op *op) { | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     auto map  = gCreator(); | 
					
						
							|  |  |  |     auto iter = map->find(op->type()); | 
					
						
							|  |  |  |     if (iter == map->end()) { | 
					
						
							| 
									
										
										
										
											2020-11-05 16:41:56 +08:00
										 |  |  |         if (nullptr != op->name()) { | 
					
						
							|  |  |  |             MNN_PRINT("Don't support type %d, %s\n", op->type(), op->name()->c_str()); | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  |             MNN_PRINT("Don't support type %d\n", op->type()); | 
					
						
							| 
									
										
										
										
											2020-11-05 16:41:56 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |         return nullptr; | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  |     auto exe = iter->second->onCreate(inputs, outputs, op, this); | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     if (nullptr == exe) { | 
					
						
							| 
									
										
										
										
											2020-11-05 16:41:56 +08:00
										 |  |  |         if (nullptr != op->name()) { | 
					
						
							|  |  |  |             MNN_PRINT("The Creator Don't support type %d, %s\n", op->type(), op->name()->c_str()); | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  |             MNN_PRINT("The Creator Don't support type %d\n", op->type()); | 
					
						
							| 
									
										
										
										
											2020-11-05 16:41:56 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |         return nullptr; | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     return exe; | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GLBackend::onExecuteEnd() const { | 
					
						
							|  |  |  |     // MNN_PRINT("Finish\n");
 | 
					
						
							|  |  |  |     // glFinish();
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GLBackend::onExecuteBegin() const { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GLBackend::onCopyBuffer(const Tensor *srcTensor, const Tensor *dstTensor) const { | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     std::vector<int> inputShape  = tensorShapeFormat(srcTensor); | 
					
						
							|  |  |  |     int ib = inputShape.at(0); | 
					
						
							|  |  |  |     int ih = inputShape.at(1); | 
					
						
							|  |  |  |     int iw = inputShape.at(2); | 
					
						
							|  |  |  |     int ic = inputShape.at(3); | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |     // OpenGL -> Host
 | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  |     if (NULL == srcTensor->buffer().host && srcTensor->buffer().device > 0) { | 
					
						
							| 
									
										
										
										
											2019-07-02 18:01:08 +08:00
										 |  |  |         if(TensorUtils::getDescribe(dstTensor)->dimensionFormat == MNN_DATA_FORMAT_NHWC){ | 
					
						
							|  |  |  |             copyImageToNhwcBuffer((GLuint)srcTensor->deviceId(), dstTensor->host<float>(), iw, ih, ic); | 
					
						
							|  |  |  |         }else{ | 
					
						
							|  |  |  |             download((GLuint)srcTensor->deviceId(), dstTensor->host<float>(), iw, ih, ic, | 
					
						
							|  |  |  |                      TensorUtils::getDescribe(dstTensor)->dimensionFormat == MNN_DATA_FORMAT_NC4HW4); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Host -> OpenGL
 | 
					
						
							|  |  |  |     }else if (NULL == dstTensor->buffer().host && dstTensor->buffer().device > 0) { | 
					
						
							|  |  |  |         if(TensorUtils::getDescribe(srcTensor)->dimensionFormat == MNN_DATA_FORMAT_NHWC){ | 
					
						
							|  |  |  |             copyNhwcBufferToImage((GLuint)dstTensor->deviceId(), srcTensor->host<float>(), iw, ih, ic); | 
					
						
							|  |  |  |         }else{ | 
					
						
							|  |  |  |             upload((GLuint)dstTensor->deviceId(), srcTensor->host<float>(), iw, ih, ic, | 
					
						
							|  |  |  |                    TensorUtils::getDescribe(srcTensor)->dimensionFormat == MNN_DATA_FORMAT_NC4HW4); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }else{ | 
					
						
							|  |  |  |         MNN_ASSERT(false); | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-12-27 22:16:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool GLBackend::onClearBuffer() { | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  |     mRuntime->mBlocks.clear(); | 
					
						
							|  |  |  |     mRuntime->mFreeTextures.clear(); | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  | class GLMemObj : public Backend::MemObj { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     GLMemObj(const Tensor *nativeTensor, uint64_t device, GLBackend::Runtime* runtime) { | 
					
						
							|  |  |  |         mTensor = nativeTensor; | 
					
						
							|  |  |  |         mDevice = device; | 
					
						
							|  |  |  |         mRuntime = runtime; | 
					
						
							| 
									
										
										
										
											2021-05-20 14:35:27 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  |     virtual ~ GLMemObj() { | 
					
						
							|  |  |  |         mRuntime->mFreeTextures.push_back(std::make_pair(mTensor, mDevice)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     const Tensor* mTensor; | 
					
						
							|  |  |  |     uint64_t mDevice; | 
					
						
							|  |  |  |     GLBackend::Runtime* mRuntime; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | Backend::MemObj* GLBackend::onAcquire(const Tensor *nativeTensor, Backend::StorageType storageType) { | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  |     auto tensor = (Tensor *)nativeTensor; | 
					
						
							| 
									
										
										
										
											2021-05-20 14:35:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // reuse only for dynamic storage
 | 
					
						
							|  |  |  |     if (Backend::DYNAMIC == storageType) { | 
					
						
							|  |  |  |         for (auto iter = mRuntime->mFreeTextures.begin(); iter != mRuntime->mFreeTextures.end(); ++iter) { | 
					
						
							|  |  |  |             auto preiousTensor = iter->first; | 
					
						
							|  |  |  |             if (preiousTensor->width() >= nativeTensor->width() && preiousTensor->height() >= nativeTensor->height() && | 
					
						
							|  |  |  |                 UP_DIV(preiousTensor->channel(), 4) >= UP_DIV(nativeTensor->channel(), 4)) { | 
					
						
							|  |  |  |                 tensor->buffer().device = iter->second; | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  |                 mRuntime->mFreeTextures.erase(iter); | 
					
						
							|  |  |  |                 return new GLMemObj(nativeTensor, tensor->buffer().device, mRuntime); | 
					
						
							| 
									
										
										
										
											2021-05-20 14:35:27 +08:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |     std::shared_ptr<GLTexture> newTexture(new GLTexture(nativeTensor->width(), nativeTensor->height(), nativeTensor->channel(), getTextrueFormat())); | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  |     tensor->buffer().device = newTexture->id(); | 
					
						
							|  |  |  |     mRuntime->mBlocks.push_back(std::move(newTexture)); | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  |     if (Backend::DYNAMIC == storageType) { | 
					
						
							|  |  |  |         return new GLMemObj(nativeTensor, tensor->buffer().device, mRuntime); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return new Backend::MemObj; | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::shared_ptr<GLProgram> GLBackend::getProgram(const std::string &key, const char *content, | 
					
						
							|  |  |  |                                                  const std::vector<std::string> &prefix) { | 
					
						
							|  |  |  |     if (key.empty()) { | 
					
						
							|  |  |  |         return getTreatedProgramWithPrefix(content, prefix); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Generate New Key
 | 
					
						
							|  |  |  |     std::ostringstream newKey; | 
					
						
							|  |  |  |     for (auto s : prefix) { | 
					
						
							|  |  |  |         newKey << s; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     newKey << key; | 
					
						
							|  |  |  |     auto newKeyStr = newKey.str(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto iter = mRuntime->mProgramCache.find(newKeyStr); | 
					
						
							|  |  |  |     if (iter != mRuntime->mProgramCache.end()) { | 
					
						
							|  |  |  |         return iter->second; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     auto program = getTreatedProgramWithPrefix(content, prefix); | 
					
						
							|  |  |  |     mRuntime->mProgramCache.insert(std::make_pair(newKeyStr, program)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return program; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::shared_ptr<GLProgram> GLBackend::getProgram(const std::string &key, const char *content) { | 
					
						
							|  |  |  |     if (key.empty()) { | 
					
						
							|  |  |  |         return getTreatedProgram(content); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     auto iter = mRuntime->mProgramCache.find(key); | 
					
						
							|  |  |  |     if (iter != mRuntime->mProgramCache.end()) { | 
					
						
							|  |  |  |         return iter->second; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     auto program = getTreatedProgram(content); | 
					
						
							|  |  |  |     mRuntime->mProgramCache.insert(std::make_pair(key, program)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return program; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  | bool GLBackend::isCreateError() const { | 
					
						
							|  |  |  |     return mIsCreateError; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-11-05 16:41:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-08 15:34:23 +08:00
										 |  |  | Backend* GLRuntime::onCreate(const BackendConfig* config) const { | 
					
						
							| 
									
										
										
										
											2020-11-05 16:41:56 +08:00
										 |  |  |     BackendConfig::PrecisionMode precision = BackendConfig::Precision_Normal; | 
					
						
							|  |  |  |     BackendConfig::PowerMode power         = BackendConfig::Power_Normal; | 
					
						
							|  |  |  |     if (nullptr != mInfo.user) { | 
					
						
							|  |  |  |         precision = mInfo.user->precision; | 
					
						
							|  |  |  |         power     = mInfo.user->power; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     auto backend = new GLBackend(precision, power); | 
					
						
							|  |  |  |     return backend; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  | int GLRuntime::onGetRuntimeStatus(RuntimeStatus statusEnum) const { | 
					
						
							|  |  |  |     MNN_ERROR("in GLRuntime\n"); | 
					
						
							|  |  |  |     switch (statusEnum) { | 
					
						
							|  |  |  |         case STATUS_SUPPORT_FP16: { | 
					
						
							|  |  |  |             return GLBackend::getOpenGLExtensions("GL_EXT_color_buffer_half_float"); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         case STATUS_SUPPORT_DOT_PRODUCT: { | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         default: { | 
					
						
							|  |  |  |             MNN_ERROR("unsupported interface"); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 16:41:56 +08:00
										 |  |  | Runtime::CompilerType GLRuntime::onGetCompilerType() const { | 
					
						
							|  |  |  |     return Compiler_Origin; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class GLRuntimeCreator : public RuntimeCreator { | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2020-11-05 16:41:56 +08:00
										 |  |  |     virtual Runtime *onCreate(const Backend::Info &info) const override { | 
					
						
							|  |  |  |         auto rt = new GLRuntime(info); | 
					
						
							| 
									
										
										
										
											2021-04-08 15:34:23 +08:00
										 |  |  |         auto bn = (GLBackend*)(rt->onCreate(nullptr)); | 
					
						
							| 
									
										
										
										
											2020-11-05 16:41:56 +08:00
										 |  |  |         if (bn->isCreateError()) { | 
					
						
							|  |  |  |             delete bn; | 
					
						
							|  |  |  |             delete rt; | 
					
						
							|  |  |  |             return nullptr; | 
					
						
							| 
									
										
										
											
												- 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
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-11-05 16:41:56 +08:00
										 |  |  |         delete bn; | 
					
						
							|  |  |  |         return rt; | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  | bool placeholder = []() { | 
					
						
							|  |  |  |     static std::once_flag createOnce; | 
					
						
							|  |  |  |     std::call_once(createOnce, []() { | 
					
						
							| 
									
										
										
										
											2023-07-18 09:36:26 +08:00
										 |  |  |         MNNInsertExtraRuntimeCreator(MNN_FORWARD_OPENGL, new GLRuntimeCreator, false); | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-07-25 13:36:35 +08:00
										 |  |  |     return true; | 
					
						
							|  |  |  | }(); | 
					
						
							| 
									
										
										
										
											2021-11-30 10:10:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-24 11:26:54 +08:00
										 |  |  | } // namespace OpenGL
 | 
					
						
							| 
									
										
										
										
											2019-04-17 10:49:11 +08:00
										 |  |  | } // namespace MNN
 |