mirror of https://github.com/alibaba/MNN.git
209 lines
6.8 KiB
C++
209 lines
6.8 KiB
C++
//
|
|
// VulkanRuntime.cpp
|
|
// MNN
|
|
//
|
|
// Created by MNN on b'2020/06/06'.
|
|
// Copyright © 2018, Alibaba Group Holding Limited
|
|
//
|
|
|
|
#include "VulkanRuntime.hpp"
|
|
#include "VulkanBackend.hpp"
|
|
namespace MNN {
|
|
class VulkanBufferAllocator : public BufferAllocator::Allocator {
|
|
public:
|
|
VulkanBufferAllocator(const VulkanDevice& device, const VulkanMemoryPool& pool) : mDevice(device), mPool(pool) {
|
|
// Do nothing
|
|
}
|
|
virtual ~ VulkanBufferAllocator() {
|
|
// Do nothing
|
|
}
|
|
virtual MemChunk onAlloc(size_t size, size_t align) override {
|
|
VulkanBuffer* newBuffer = new VulkanBuffer(mPool, false, size, nullptr, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE, 0);
|
|
return MemChunk(newBuffer, 0);
|
|
}
|
|
virtual void onRelease(MemChunk ptr) override {
|
|
auto p = (VulkanBuffer*)ptr.first;
|
|
delete p;
|
|
}
|
|
private:
|
|
const VulkanDevice& mDevice;
|
|
const VulkanMemoryPool& mPool;
|
|
};
|
|
|
|
|
|
float VulkanRuntime::onGetMemoryInMB() {
|
|
return mMemoryPool->computeSize();
|
|
}
|
|
|
|
VulkanRuntime::VulkanRuntime(const Backend::Info& info) {
|
|
mInfo = info;
|
|
MNNVulkanContext* context = nullptr;
|
|
if (nullptr != info.user && nullptr != info.user->sharedContext) {
|
|
MNN_PRINT("Use user's vulkan context\n");
|
|
context = static_cast<MNNVulkanContext*>(info.user->sharedContext);
|
|
}
|
|
if (NULL != context) {
|
|
mInstance = std::make_shared<VulkanInstance>(context->pInstance);
|
|
mDevice = std::make_shared<VulkanDevice>(mInstance, context->pPhysicalDevice, context->pDevice,
|
|
context->iQueueFamilyIndex, context->pQueue);
|
|
} else {
|
|
mInstance = std::make_shared<VulkanInstance>();
|
|
mDevice = std::make_shared<VulkanDevice>(mInstance);
|
|
}
|
|
auto& dev = *mDevice;
|
|
mCmdPool = std::make_shared<VulkanCommandPool>(dev);
|
|
//GFlops, Test by mobilenet v1's ms
|
|
static std::map<std::string, float> gFlopsMap {
|
|
{"Mali-T860", 6.83f},
|
|
{"Mali-T880", 6.83f},
|
|
{"Mali-G51", 6.83f},
|
|
{"Mali-G52", 6.83f},
|
|
{"Mali-G71", 31.61f},
|
|
{"Mali-G72", 31.61f},
|
|
{"Mali-G76", 31.61f},
|
|
{"Adreno (TM) 505", 3.19f},
|
|
{"Adreno (TM) 506", 4.74f},
|
|
{"Adreno (TM) 512", 14.23f},
|
|
{"Adreno (TM) 530", 25.40f},
|
|
{"Adreno (TM) 540", 42.74f},
|
|
{"Adreno (TM) 615", 16.77f},
|
|
{"Adreno (TM) 616", 18.77f},
|
|
{"Adreno (TM) 618", 18.77f},
|
|
{"Adreno (TM) 630", 42.74f},
|
|
{"Adreno (TM) 640", 42.74f},
|
|
};
|
|
mFlops = 4.0f;//Default set as 4G, it will be larger than single-core cpu
|
|
std::string deviceName = dev.proty().deviceName;
|
|
//FUNC_PRINT_ALL(deviceName.c_str(), s);
|
|
if (gFlopsMap.find(deviceName)!=gFlopsMap.end()) {
|
|
mFlops = gFlopsMap[deviceName];
|
|
}
|
|
//FUNC_PRINT_ALL(mFlops, f);
|
|
|
|
if (deviceName.find("Mali") != std::string::npos) {
|
|
mGpuType = MALI;
|
|
} else if (deviceName.find("Adreno") != std::string::npos) {
|
|
mGpuType = ADRENO;
|
|
}
|
|
bool fp16 = true;
|
|
if (info.user != nullptr) {
|
|
fp16 = info.user->precision != BackendConfig::Precision_High;
|
|
}
|
|
mMemoryPool = std::make_shared<VulkanMemoryPool>(dev, fp16);
|
|
std::shared_ptr<BufferAllocator::Allocator> allocReal(new VulkanBufferAllocator(dev, *mMemoryPool));
|
|
mBufferPool.reset(new EagerBufferAllocator(allocReal, dev.proty().limits.nonCoherentAtomSize));
|
|
mSampler = std::make_shared<VulkanSampler>(dev, VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER);
|
|
mClampSampler = std::make_shared<VulkanSampler>(dev, VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
|
|
mPipelineFactory = std::make_shared<VulkanPipelineFactory>(dev);
|
|
mQueryPool = std::make_shared<VulkanQueryPool>(dev);
|
|
}
|
|
|
|
VulkanRuntime::~VulkanRuntime() {
|
|
mBufferPool = nullptr;
|
|
while (!mUniformCache.empty()) {
|
|
mUniformCache.pop();
|
|
}
|
|
mQueryPool = nullptr;
|
|
mCmdPool = nullptr;
|
|
mSampler = nullptr;
|
|
mClampSampler = nullptr;
|
|
mPipelineFactory = nullptr;
|
|
mMemoryPool = nullptr;
|
|
mDevice = nullptr;
|
|
mInstance = nullptr;
|
|
}
|
|
std::shared_ptr<VulkanBuffer> VulkanRuntime::allocUniform(const void* src, int size) {
|
|
std::shared_ptr<VulkanBuffer> res;
|
|
int allocSize = size;
|
|
if (allocSize < mUniformSize) {
|
|
allocSize = mUniformSize;
|
|
}
|
|
if (mUniformCache.empty() || allocSize > mUniformSize) {
|
|
res = std::shared_ptr<VulkanBuffer>(new VulkanBuffer(*mMemoryPool, false, allocSize, nullptr, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT));
|
|
} else {
|
|
res = mUniformCache.front();
|
|
mUniformCache.pop();
|
|
}
|
|
if (nullptr != src) {
|
|
auto dst = res->map();
|
|
::memcpy(dst, src, size);
|
|
res->unmap();
|
|
}
|
|
return res;
|
|
}
|
|
void VulkanRuntime::recycleUniform(std::shared_ptr<VulkanBuffer> buffer) {
|
|
if (buffer->size() < mUniformSize) {
|
|
return;
|
|
}
|
|
if (mUniformCache.size() >= mCacheUniformLimitSize) {
|
|
return;
|
|
}
|
|
mUniformCache.push(buffer);
|
|
}
|
|
|
|
void VulkanRuntime::onGabageCollect(int level) {
|
|
mBufferPool->release(false);
|
|
mMemoryPool->clear();
|
|
mPipelineFactory->reset();
|
|
}
|
|
|
|
Backend* VulkanRuntime::onCreate(const BackendConfig* config) const {
|
|
// FIXME: Use config
|
|
return new VulkanBackend(this, mInfo);
|
|
}
|
|
int VulkanRuntime::onGetRuntimeStatus(RuntimeStatus statusEnum) const {
|
|
switch (statusEnum) {
|
|
case STATUS_SUPPORT_FP16: {
|
|
return 1;
|
|
break;
|
|
}
|
|
case STATUS_SUPPORT_DOT_PRODUCT: {
|
|
return 0;
|
|
break;
|
|
}
|
|
default: {
|
|
MNN_ERROR("unsupported interface");
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
static bool _testVulkan() {
|
|
// std::make_unique need c++14
|
|
std::unique_ptr<VulkanInstance> instance(new VulkanInstance());
|
|
if (nullptr == instance) {
|
|
MNN_ERROR("Invalide device for support vulkan\n");
|
|
return false;
|
|
}
|
|
if (!instance->success()) {
|
|
MNN_ERROR("Invalide device for support vulkan\n");
|
|
return false;
|
|
}
|
|
if (!instance->supportVulkan()) {
|
|
MNN_ERROR("Invalide device for support vulkan\n");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
class VulkanRuntimeCreator : public RuntimeCreator {
|
|
public:
|
|
virtual Runtime* onCreate(const Backend::Info& info) const {
|
|
if (InitVulkan()) {
|
|
if (_testVulkan()) {
|
|
return new VulkanRuntime(info);
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
virtual bool onValid(Backend::Info& info) const {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
static bool gResistor = []() {
|
|
MNNInsertExtraRuntimeCreator(MNN_FORWARD_VULKAN, new VulkanRuntimeCreator, true);
|
|
return false;
|
|
}();
|
|
}
|