Files
2026-07-13 13:33:03 +08:00

86 lines
3.7 KiB
C++

#ifndef VulkanConv1x1CoopA8_hpp
#define VulkanConv1x1CoopA8_hpp
#include "VulkanBasicExecution.hpp"
#include "VulkanConvolution.hpp"
#include "core/ConvolutionCommon.hpp"
namespace MNN {
// W8A8 cooperative-matrix Conv1x1 path (per-channel asym int8 OR int4 +
// Adreno + S8S8->S32 coop matrix). M==1 reuses Coop-A16's gemv_dequant decode
// (int4/int8 variant); M>1 runs a 6-stage dynamic-quant -> S8 GEMM ->
// dequant-correction pipeline. INT4 mode adds a runtime int4->int8 unpack
// stage so the GEMM body is shared with INT8.
class VulkanConv1x1CoopA8 : public VulkanBasicExecution {
public:
VulkanConv1x1CoopA8(VulkanBackend* backend, const Convolution2DCommon* convOption,
const float* biasPtr, int ci, int co,
VulkanDevice::CoopMatInfo coopMatInfo,
std::shared_ptr<ConvolutionCommon::Int8Common> quantInfo);
virtual ~VulkanConv1x1CoopA8();
virtual ErrorCode onEncode(const std::vector<Tensor*>& inputs, const std::vector<Tensor*>& outputs,
const VulkanCommandPool::Buffer* cmdBuffer) override;
virtual bool onClone(Backend* bn, const Op* op, VulkanBasicExecution** dst) override;
private:
VulkanConv1x1CoopA8(VulkanBackend* backend, const Convolution2DCommon* convOption, int ci, int co,
uint32_t coopM, uint32_t coopN, uint32_t coopK, uint32_t subgroupSize,
std::shared_ptr<ConvolutionCommon::Int8Common> quantInfo,
bool initStaticResource);
bool _init(const float* biasPtr, bool initStaticResource);
const Convolution2DCommon* mCommon;
int mCi;
int mCo;
std::shared_ptr<ConvolutionCommon::Int8Common> mQuantCommon;
uint32_t mPadK = 0;
uint32_t mPadN = 0;
// Static buffers — decode + prefill share, onClone forwards them.
// mQuantWeightBuffer: INT8: [padN, padK/4] uint32 (4x int8 packed).
// INT4: [padN, padK/8] uint32 (8x int4 packed,
// unsigned 0..15 with host +8 offset).
// mQuantMetaBuffer: [padN, 2] FP interleaved (scale, offset).
// mSumWqBuffer: [padN] int32, sum_k Wq[n,k]; padding rows zero.
std::shared_ptr<VulkanBuffer> mBiasBuffer;
std::shared_ptr<VulkanBuffer> mQuantWeightBuffer;
std::shared_ptr<VulkanBuffer> mQuantMetaBuffer;
std::shared_ptr<VulkanBuffer> mSumWqBuffer;
const VulkanPipeline* mDecodePipeline = nullptr;
std::shared_ptr<VulkanLayout::DescriptorSet> mDecodeSet;
// INT4 prefill only: runtime nibble unpack from mQuantWeightBuffer to
// a dynamic [padN, padK] int8 tensor (tWqInt8 in onEncode), then the
// shared dynamic_w8a8_coop_gemm consumes it as if it were INT8.
const VulkanPipeline* mInt4UnpackPipeline = nullptr;
std::shared_ptr<VulkanLayout::DescriptorSet> mInt4UnpackSet;
const VulkanPipeline* mQuantMinMaxPipeline = nullptr;
const VulkanPipeline* mQuantReduceMinMaxPipeline = nullptr;
const VulkanPipeline* mQuantPackPipeline = nullptr;
const VulkanPipeline* mQuantReduceSumPipeline = nullptr;
const VulkanPipeline* mGemmS8Pipeline = nullptr;
const VulkanPipeline* mDequantPipeline = nullptr;
std::shared_ptr<VulkanLayout::DescriptorSet> mQuantMinMaxSet;
std::shared_ptr<VulkanLayout::DescriptorSet> mQuantReduceMinMaxSet;
std::shared_ptr<VulkanLayout::DescriptorSet> mQuantPackSet;
std::shared_ptr<VulkanLayout::DescriptorSet> mQuantReduceSumSet;
std::shared_ptr<VulkanLayout::DescriptorSet> mGemmSet;
std::shared_ptr<VulkanLayout::DescriptorSet> mDequantSet;
uint32_t mCoopM = 64;
uint32_t mCoopN = 64;
uint32_t mCoopK = 32;
uint32_t mSubgroupSize = 64;
bool mIsInt4 = false;
};
} // namespace MNN
#endif