chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,443 @@
|
||||
//
|
||||
// VulkanMatMul.cpp
|
||||
// MNN
|
||||
//
|
||||
// Created by MNN on 2020/03/06.
|
||||
// Copyright © 2018, Alibaba Group Holding Limited
|
||||
//
|
||||
|
||||
#include "VulkanMatMul.hpp"
|
||||
#include "core/TensorUtils.hpp"
|
||||
namespace MNN {
|
||||
|
||||
class TexturePosComputer {
|
||||
public:
|
||||
TexturePosComputer(const Tensor* tensor) {
|
||||
mFormat = TensorUtils::getDescribe(tensor)->dimensionFormat;
|
||||
mNHWC = VulkanTensor::tensorShapeFormat(tensor);
|
||||
}
|
||||
~ TexturePosComputer() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
// X, Y, rgba
|
||||
std::array<int, 3> computePos(int offset) const {
|
||||
std::array<int, 4> nhwcPos;
|
||||
if (mFormat == MNN_DATA_FORMAT_NHWC) {
|
||||
// NHWC
|
||||
nhwcPos[3] = offset % mNHWC[3];
|
||||
offset = (offset - nhwcPos[3]) / mNHWC[3];
|
||||
nhwcPos[2] = offset % mNHWC[2];
|
||||
offset = (offset - nhwcPos[2]) / mNHWC[2];
|
||||
nhwcPos[1] = offset % mNHWC[1];
|
||||
nhwcPos[0] = offset / mNHWC[1];
|
||||
} else {
|
||||
// NCHW
|
||||
nhwcPos[2] = offset % mNHWC[2];
|
||||
offset = offset / mNHWC[2];
|
||||
nhwcPos[1] = offset % mNHWC[1];
|
||||
offset = offset / mNHWC[1];
|
||||
nhwcPos[3] = offset % mNHWC[3];
|
||||
nhwcPos[0] = offset / mNHWC[3];
|
||||
}
|
||||
// MNN_PRINT("n, c, h, w: %d, %d, %d, %d\n", nhwcPos[0], nhwcPos[3], nhwcPos[1], nhwcPos[2]);
|
||||
std::array<int, 3> res;
|
||||
res[2] = nhwcPos[3] % 4;
|
||||
auto c4 = nhwcPos[3] / 4;
|
||||
res[0] = c4 * mNHWC[2] + nhwcPos[2];
|
||||
res[1] = nhwcPos[0] * mNHWC[1] + nhwcPos[1];
|
||||
return res;
|
||||
}
|
||||
private:
|
||||
MNN_DATA_FORMAT mFormat;
|
||||
std::array<int, 4> mNHWC;
|
||||
};
|
||||
|
||||
VulkanMatMul::Reorder::Reorder(const VulkanBackend* bn, bool transpose, bool revert) {
|
||||
std::vector<VkDescriptorType> types{
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
|
||||
};
|
||||
if (revert) {
|
||||
mFirst = bn->getPipeline("glsl_nc4hw4Tonchw_comp", types);
|
||||
} else {
|
||||
mFirst = bn->getPipeline("glsl_nchwTonc4hw4_comp", types);
|
||||
}
|
||||
mBufferBufferSet.reset(mFirst->createSet());
|
||||
mBackend = bn;
|
||||
mUnitBuffer.reset(new VulkanBuffer(bn->getMemoryPool(), false, sizeof(nchwBuffer), nullptr, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT));
|
||||
std::string imageShaderName = "glsl_packAsImage4x4";
|
||||
std::vector<VkDescriptorType> secondTypes{
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
|
||||
};
|
||||
|
||||
if (revert) {
|
||||
secondTypes[0] = VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||
imageShaderName = "glsl_unPackImage4x4";
|
||||
}
|
||||
if (transpose) {
|
||||
imageShaderName = imageShaderName + "_TRANSPOSE_comp";
|
||||
} else {
|
||||
imageShaderName = imageShaderName + "_comp";
|
||||
}
|
||||
mSecond = bn->getPipeline(imageShaderName, secondTypes);
|
||||
mImageBufferSet.reset(mSecond->createSet());
|
||||
}
|
||||
|
||||
void VulkanMatMul::Reorder::encode(VkBuffer source, size_t sourceSize, VkBuffer middleBuffer, size_t middelBufferSize, const VulkanImage* dest, const VulkanCommandPool::Buffer* cmdBuffer, const VulkanMatMul::Reorder::nchwBuffer& buffer) {
|
||||
// First: nchw to nc4hw4
|
||||
auto ptr = (nchwBuffer*)mUnitBuffer->map();
|
||||
::memcpy(ptr, &buffer, sizeof(buffer));
|
||||
mUnitBuffer->unmap();
|
||||
auto c = buffer.size[1];
|
||||
auto b = buffer.size[0];
|
||||
auto w = buffer.size[3];
|
||||
auto h = buffer.size[2];
|
||||
auto cDiv4 = UP_DIV(c, 4);
|
||||
mBufferBufferSet->writeBuffer(middleBuffer, 1, middelBufferSize);
|
||||
mBufferBufferSet->writeBuffer(source, 0, sourceSize, 0);
|
||||
mBufferBufferSet->writeBuffer(mUnitBuffer->buffer(), 2, mUnitBuffer->size());
|
||||
auto totalNumber = cDiv4 * w * h * b;
|
||||
|
||||
mFirst->bind(cmdBuffer->get(), mBufferBufferSet->get());
|
||||
cmdBuffer->barrierSource(source, 0, sourceSize);
|
||||
vkCmdDispatch(cmdBuffer->get(), UP_DIV(totalNumber, 256), 1, 1);
|
||||
|
||||
// Second: nc4hw4 to image2d
|
||||
dest->barrierWrite(cmdBuffer->get());
|
||||
mImageBufferSet->writeImage(dest->view(), mBackend->getCommonSampler()->get(), VK_IMAGE_LAYOUT_GENERAL, 0);
|
||||
mImageBufferSet->writeBuffer(middleBuffer, 1, middelBufferSize);
|
||||
mImageBufferSet->writeBuffer(mUnitBuffer->buffer(), 2, mUnitBuffer->size());
|
||||
mSecond->bind(cmdBuffer->get(), mImageBufferSet->get());
|
||||
cmdBuffer->barrierSource(middleBuffer, 0, middelBufferSize);
|
||||
auto totalSchedule = cDiv4 * w * h * UP_DIV(b, 4);
|
||||
vkCmdDispatch(cmdBuffer->get(), UP_DIV(totalSchedule, 256), 1, 1);
|
||||
}
|
||||
int VulkanMatMul::Reorder::computeMiddleBufferSize(int b, int h, int w, int c) const {
|
||||
auto cDiv4 = UP_DIV(c, 4);
|
||||
auto totalNumber = cDiv4 * w * h * b;
|
||||
return totalNumber * 4;
|
||||
}
|
||||
void VulkanMatMul::Reorder::revert(VkBuffer dest, size_t destSize, VkBuffer middleBuffer, size_t middelBufferSize, const VulkanImage* source, const VulkanCommandPool::Buffer* cmdBuffer, const VulkanMatMul::Reorder::nchwBuffer& buffer) {
|
||||
// First: nchw to nc4hw4
|
||||
auto ptr = (nchwBuffer*)mUnitBuffer->map();
|
||||
::memcpy(ptr, &buffer, sizeof(buffer));
|
||||
mUnitBuffer->unmap();
|
||||
auto c = buffer.size[1];
|
||||
auto b = buffer.size[0];
|
||||
auto w = buffer.size[3];
|
||||
auto h = buffer.size[2];
|
||||
auto cDiv4 = UP_DIV(c, 4);
|
||||
// First: image2d to nc4hw4
|
||||
mImageBufferSet->writeImage(source->view(), mBackend->getCommonSampler()->get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0);
|
||||
mImageBufferSet->writeBuffer(middleBuffer, 1, middelBufferSize);
|
||||
mImageBufferSet->writeBuffer(mUnitBuffer->buffer(), 2, mUnitBuffer->size());
|
||||
mSecond->bind(cmdBuffer->get(), mImageBufferSet->get());
|
||||
auto totalSchedule = cDiv4 * w * h * UP_DIV(b, 4);
|
||||
source->barrierRead(cmdBuffer->get());
|
||||
// cmdBuffer->barrierImage(source->get(), VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
vkCmdDispatch(cmdBuffer->get(), UP_DIV(totalSchedule, 256), 1, 1);
|
||||
|
||||
// Second: nc4hw4 to nchw
|
||||
mBufferBufferSet->writeBuffer(middleBuffer, 1, middelBufferSize);
|
||||
mBufferBufferSet->writeBuffer(dest, 0, destSize, 0);
|
||||
mBufferBufferSet->writeBuffer(mUnitBuffer->buffer(), 2, mUnitBuffer->size());
|
||||
auto totalNumber = cDiv4 * w * h * b;
|
||||
mFirst->bind(cmdBuffer->get(), mBufferBufferSet->get());
|
||||
cmdBuffer->barrierSource(middleBuffer, 0, middelBufferSize);
|
||||
vkCmdDispatch(cmdBuffer->get(), UP_DIV(totalNumber, 256), 1, 1);
|
||||
}
|
||||
|
||||
VulkanMatMul::VulkanMatMul(bool transposeA, bool transposeB, Backend* bn) : VulkanBasicExecution(bn) {
|
||||
mTransposeA = transposeA;
|
||||
mTransposeB = transposeB;
|
||||
}
|
||||
|
||||
bool VulkanMatMul::encode(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs,
|
||||
const VulkanCommandPool::Buffer *cmdBuffer, const MatMulInfo& info) {
|
||||
mTempBuffer.clear();
|
||||
mSets.clear();
|
||||
auto input0T = reinterpret_cast<VulkanTensor*>(inputs[0]->deviceId());
|
||||
auto input1T = reinterpret_cast<VulkanTensor*>(inputs[1]->deviceId());
|
||||
auto outputT = reinterpret_cast<VulkanTensor*>(outputs[0]->deviceId());
|
||||
if (input0T->imageSize() > 1 || input1T->imageSize() > 1 || outputT->imageSize() > 1) {
|
||||
// TODO: Copy to temp buffer
|
||||
return false;
|
||||
}
|
||||
auto types = std::vector<VkDescriptorType>{
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
};
|
||||
const VulkanPipeline* mInputPipline = nullptr;
|
||||
const VulkanPipeline* mWeightPipline = nullptr;
|
||||
const VulkanPipeline* mOutputPipeline = nullptr;
|
||||
auto vkBn = static_cast<VulkanBackend*>(backend());
|
||||
int e = info.e;
|
||||
int l = info.l;
|
||||
int h = info.h;
|
||||
struct OffsetBuffer {
|
||||
ivec4 size;
|
||||
float transpose[16];
|
||||
};
|
||||
{
|
||||
// Pretreat B
|
||||
// Turn bStride(e, l, h) -> x,y + offset
|
||||
// MNN_PRINT("Compute B %d x %d:\n", inputs[1]->length(0), inputs[1]->length(1));
|
||||
TexturePosComputer comp(inputs[1]);
|
||||
auto offset0 = comp.computePos(info.offsetB);
|
||||
if (offset0[2] != 0) {
|
||||
return false;
|
||||
}
|
||||
auto offsetl = comp.computePos(info.bStride[1]);
|
||||
auto offseth = comp.computePos(info.bStride[2]);
|
||||
bool transposeB = offsetl[2] == 1;
|
||||
if (l == 1) {
|
||||
// TODO: Find better way
|
||||
transposeB = offseth[2] == 0;
|
||||
}
|
||||
int l_W = offsetl[0] * 4 + offsetl[2];
|
||||
int l_H = offsetl[1] * 4;
|
||||
int h_W = offseth[0] * 4 + offseth[2];
|
||||
int h_H = offseth[1] * 4;
|
||||
// MNN_PRINT("Compute B: %d x %d, %d-%d-%d, %d-%d-%d\n", info.bStride[1], info.bStride[2], offsetl[0], offsetl[1], offsetl[2], offseth[0], offseth[1], offseth[2]);
|
||||
if (transposeB) {
|
||||
mWeightPipline = vkBn->getPipeline("glsl_matmul_input_TRANSPOSE_comp", types);
|
||||
} else {
|
||||
mWeightPipline = vkBn->getPipeline("glsl_matmul_input_comp", types);
|
||||
}
|
||||
mKernelImage.reset(new VulkanImage(vkBn->getDynamicMemoryPool(), false, {ALIGN_UP4(l), UP_DIV(h, 4)}));
|
||||
std::shared_ptr<VulkanLayout::DescriptorSet> des(mWeightPipline->createSet());
|
||||
OffsetBuffer buffer;
|
||||
buffer.size[0] = UP_DIV(l, 4);
|
||||
buffer.size[1] = UP_DIV(h, 4);
|
||||
if (transposeB) {
|
||||
buffer.size[2] = h;
|
||||
} else {
|
||||
buffer.size[2] = l;
|
||||
}
|
||||
buffer.size[2] = buffer.size[2] + offset0[1];
|
||||
buffer.size[3] = UP_DIV(l, 4) * UP_DIV(h, 4);
|
||||
::memset(buffer.transpose, 0, 16 * sizeof(float));
|
||||
buffer.transpose[4 * 0 + 0] = l_W;
|
||||
buffer.transpose[4 * 0 + 1] = h_W;
|
||||
buffer.transpose[4 * 0 + 2] = 0;
|
||||
buffer.transpose[4 * 0 + 3] = offset0[0];
|
||||
|
||||
buffer.transpose[4 * 1 + 0] = l_H;
|
||||
buffer.transpose[4 * 1 + 1] = h_H;
|
||||
buffer.transpose[4 * 1 + 2] = 0;
|
||||
buffer.transpose[4 * 1 + 3] = offset0[1];
|
||||
std::shared_ptr<VulkanBuffer> uniformBuffer(new VulkanBuffer(vkBn->getMemoryPool(), false, sizeof(OffsetBuffer), &buffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT));
|
||||
des->writeBuffer(uniformBuffer->buffer(), 2, uniformBuffer->size());
|
||||
des->writeImage(mKernelImage->view(), vkBn->getCommonSampler()->get(), VK_IMAGE_LAYOUT_GENERAL, 0);
|
||||
des->writeImage(input1T->image()->view(), vkBn->getCommonSampler()->get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1);
|
||||
mTempBuffer.emplace_back(uniformBuffer);
|
||||
mSets.emplace_back(des);
|
||||
mWeightPipline->bind(cmdBuffer->get(), des->get());
|
||||
|
||||
input1T->image()->barrierRead(cmdBuffer->get());
|
||||
mKernelImage->barrierWrite(cmdBuffer->get());
|
||||
|
||||
vkCmdDispatch(cmdBuffer->get(), UP_DIV(buffer.size[3], 256), 1, 1);
|
||||
}
|
||||
{
|
||||
// Pretreat A
|
||||
TexturePosComputer comp(inputs[0]);
|
||||
auto offset0 = comp.computePos(info.offsetA);
|
||||
if (offset0[2] != 0) {
|
||||
return false;
|
||||
}
|
||||
auto offsetl = comp.computePos(info.aStride[1]);
|
||||
auto offsete = comp.computePos(info.aStride[0]);
|
||||
int l_W = offsetl[0] * 4 + offsetl[2];
|
||||
int l_H = offsetl[1] * 4;
|
||||
int e_W = offsete[0] * 4 + offsete[2];
|
||||
int e_H = offsete[1] * 4;
|
||||
bool transposeA = offsetl[2] != 1;
|
||||
if (l == 1) {
|
||||
// TODO: Find better way
|
||||
transposeA = offsete[2] == 1;
|
||||
}
|
||||
if (!transposeA) {
|
||||
mInputPipline = vkBn->getPipeline("glsl_matmul_input_comp", types);
|
||||
} else {
|
||||
mInputPipline = vkBn->getPipeline("glsl_matmul_input_TRANSPOSE_comp", types);
|
||||
}
|
||||
mInputImage.reset(new VulkanImage(vkBn->getDynamicMemoryPool(), false, {ALIGN_UP4(l), UP_DIV(e, 4)}));
|
||||
std::shared_ptr<VulkanLayout::DescriptorSet> des(mInputPipline->createSet());
|
||||
OffsetBuffer buffer;
|
||||
buffer.size[0] = UP_DIV(l, 4);
|
||||
buffer.size[1] = UP_DIV(e, 4);
|
||||
if (transposeA) {
|
||||
buffer.size[2] = l;
|
||||
} else {
|
||||
buffer.size[2] = e;
|
||||
}
|
||||
buffer.size[2] = buffer.size[2] + offset0[1];
|
||||
buffer.size[3] = UP_DIV(l, 4) * UP_DIV(e, 4);
|
||||
::memset(buffer.transpose, 0, 16 * sizeof(float));
|
||||
buffer.transpose[4 * 0 + 0] = l_W;
|
||||
buffer.transpose[4 * 0 + 1] = e_W;
|
||||
buffer.transpose[4 * 0 + 2] = 0;
|
||||
buffer.transpose[4 * 0 + 3] = offset0[0];
|
||||
|
||||
buffer.transpose[4 * 1 + 0] = l_H;
|
||||
buffer.transpose[4 * 1 + 1] = e_H;
|
||||
buffer.transpose[4 * 1 + 2] = 0;
|
||||
buffer.transpose[4 * 1 + 3] = offset0[1];
|
||||
std::shared_ptr<VulkanBuffer> uniformBuffer(new VulkanBuffer(vkBn->getMemoryPool(), false, sizeof(OffsetBuffer), &buffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT));
|
||||
des->writeBuffer(uniformBuffer->buffer(), 2, uniformBuffer->size());
|
||||
des->writeImage(mInputImage->view(), vkBn->getCommonSampler()->get(), VK_IMAGE_LAYOUT_GENERAL, 0);
|
||||
des->writeImage(input0T->image()->view(), vkBn->getCommonSampler()->get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1);
|
||||
mTempBuffer.emplace_back(uniformBuffer);
|
||||
mSets.emplace_back(des);
|
||||
mInputPipline->bind(cmdBuffer->get(), des->get());
|
||||
|
||||
input0T->image()->barrierRead(cmdBuffer->get());
|
||||
mInputImage->barrierWrite(cmdBuffer->get());
|
||||
|
||||
vkCmdDispatch(cmdBuffer->get(), UP_DIV(buffer.size[3], 256), 1, 1);
|
||||
}
|
||||
mCore.reset(new VulkanMatrixMultier4x4(vkBn, nullptr, l, h, 1, mKernelImage));
|
||||
mOutputImage.reset(new VulkanImage(vkBn->getDynamicMemoryPool(), false, {ALIGN_UP4(h), UP_DIV(e, 4)}));
|
||||
mCore->prepare(cmdBuffer, e, mOutputImage, mInputImage);
|
||||
mCore->compute(cmdBuffer);
|
||||
mInputImage->release();
|
||||
mKernelImage->release();
|
||||
{
|
||||
// Posttreat C
|
||||
if (inputs.size() > 2) {
|
||||
auto ntypes = std::vector<VkDescriptorType>{
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
};
|
||||
mOutputPipeline = vkBn->getPipeline("glsl_matmul_output_BIAS_comp", ntypes);
|
||||
} else {
|
||||
mOutputPipeline = vkBn->getPipeline("glsl_matmul_output_comp", types);
|
||||
}
|
||||
TexturePosComputer comp(outputs[0]);
|
||||
auto offset0 = comp.computePos(info.offsetC);
|
||||
if (offset0[2] != 0) {
|
||||
return false;
|
||||
}
|
||||
auto offsete = comp.computePos(info.cStride[0]);
|
||||
auto offseth = comp.computePos(info.cStride[2]);
|
||||
|
||||
std::shared_ptr<VulkanLayout::DescriptorSet> des(mOutputPipeline->createSet());
|
||||
OffsetBuffer buffer;
|
||||
buffer.size[0] = UP_DIV(h, 4);
|
||||
buffer.size[1] = UP_DIV(e, 4);
|
||||
buffer.size[2] = e + offset0[1];
|
||||
buffer.size[3] = UP_DIV(h, 4) * UP_DIV(e, 4);
|
||||
::memset(buffer.transpose, 0, 16 * sizeof(float));
|
||||
buffer.transpose[4 * 0 + 0] = 1;
|
||||
buffer.transpose[4 * 0 + 1] = 0;
|
||||
buffer.transpose[4 * 0 + 2] = 0;
|
||||
buffer.transpose[4 * 0 + 3] = offset0[0];
|
||||
|
||||
buffer.transpose[4 * 1 + 0] = 0;
|
||||
buffer.transpose[4 * 1 + 1] = 4;
|
||||
buffer.transpose[4 * 1 + 2] = 0;
|
||||
buffer.transpose[4 * 1 + 3] = offset0[1];
|
||||
|
||||
std::shared_ptr<VulkanBuffer> uniformBuffer(new VulkanBuffer(vkBn->getMemoryPool(), false, sizeof(OffsetBuffer), &buffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT));
|
||||
des->writeBuffer(uniformBuffer->buffer(), 2, uniformBuffer->size());
|
||||
des->writeImage(outputT->image()->view(), vkBn->getCommonSampler()->get(), VK_IMAGE_LAYOUT_GENERAL, 0);
|
||||
des->writeImage(mOutputImage->view(), vkBn->getCommonSampler()->get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1);
|
||||
if (inputs.size() > 2) {
|
||||
float biasTranspose[16];
|
||||
std::shared_ptr<VulkanBuffer> biasuniformBuffer(new VulkanBuffer(vkBn->getMemoryPool(), false, sizeof(biasTranspose), &biasTranspose, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT));
|
||||
des->writeImage(reinterpret_cast<VulkanTensor*>(inputs[2]->deviceId())->image()->view(), vkBn->getCommonSampler()->get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 3);
|
||||
des->writeBuffer(biasuniformBuffer->buffer(), 4, 16 * sizeof(float));
|
||||
mTempBuffer.emplace_back(biasuniformBuffer);
|
||||
}
|
||||
mSets.emplace_back(des);
|
||||
mOutputPipeline->bind(cmdBuffer->get(), des->get());
|
||||
|
||||
outputT->image()->barrierWrite(cmdBuffer->get());
|
||||
mOutputImage->barrierRead(cmdBuffer->get());
|
||||
vkCmdDispatch(cmdBuffer->get(), UP_DIV(buffer.size[3], 256), 1, 1);
|
||||
|
||||
mTempBuffer.emplace_back(uniformBuffer);
|
||||
}
|
||||
mOutputImage->release();
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorCode VulkanMatMul::onEncode(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs,
|
||||
const VulkanCommandPool::Buffer *cmdBuffer) {
|
||||
Tensor* C = outputs[0];
|
||||
auto w0 = inputs[0]->length(1);
|
||||
auto h0 = inputs[0]->length(0);
|
||||
auto e = C->length(0);
|
||||
auto h = C->length(1);
|
||||
auto l = w0;
|
||||
if (mTransposeA) {
|
||||
l = h0;
|
||||
}
|
||||
MatMulInfo info;
|
||||
info.e = e;
|
||||
info.l = l;
|
||||
info.h = h;
|
||||
if (mTransposeA) {
|
||||
info.aStride[0] = 1;
|
||||
info.aStride[1] = e;
|
||||
info.aStride[2] = 0;
|
||||
} else {
|
||||
info.aStride[0] = l;
|
||||
info.aStride[1] = 1;
|
||||
info.aStride[2] = 0;
|
||||
}
|
||||
if (mTransposeB) {
|
||||
info.bStride[0] = 0;
|
||||
info.bStride[1] = 1;
|
||||
info.bStride[2] = l;
|
||||
} else {
|
||||
info.bStride[0] = 0;
|
||||
info.bStride[1] = h;
|
||||
info.bStride[2] = 1;
|
||||
}
|
||||
info.cStride[0] = h;
|
||||
info.cStride[1] = 0;
|
||||
info.cStride[2] = 1;
|
||||
auto res = encode(inputs, outputs, cmdBuffer, info);
|
||||
if (!res) {
|
||||
return NOT_SUPPORT;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
class VulkanMatMulCreator : public VulkanBackend::Creator {
|
||||
public:
|
||||
virtual VulkanBasicExecution* onCreate(const std::vector<Tensor*>& inputs, const std::vector<Tensor*>& outputs, const MNN::Op* op, Backend* bn) const override {
|
||||
Tensor* C = outputs[0];
|
||||
auto w0 = inputs[0]->length(1);
|
||||
auto h0 = inputs[0]->length(0);
|
||||
auto e = C->length(0);
|
||||
auto h = C->length(1);
|
||||
auto l = w0;
|
||||
auto vkBn = static_cast<VulkanBackend*>(bn);
|
||||
const auto mat = op->main_as_MatMul();
|
||||
if (mat->transposeA()) {
|
||||
l = h0;
|
||||
}
|
||||
auto limit = vkBn->proty().limits.maxImageDimension2D;
|
||||
if (e > limit || h > limit || l > limit) {
|
||||
return nullptr;
|
||||
}
|
||||
return new VulkanMatMul(mat->transposeA(), mat->transposeB(), bn);
|
||||
}
|
||||
};
|
||||
|
||||
static bool gResistor = []() {
|
||||
VulkanBackend::addCreator(OpType_MatMul, new VulkanMatMulCreator);
|
||||
return true;
|
||||
}();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user