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

163 lines
7.9 KiB
Plaintext

#version 440 core
#if defined(FP16) || defined(RELU_FP16) || defined(RELU6_FP16)
#extension GL_AMD_gpu_shader_half_float: enable
#define FLOAT4 f16vec4
#else
#define FLOAT4 vec4
#endif
layout(set=0, binding=0) writeonly uniform image2D uOutput;
layout(set=0, binding=1) uniform sampler2D uInput;
layout(set=0, binding=2) uniform sampler2D uKernel;
layout(set=0, binding=3) uniform sampler2D uBias;
layout(set=0, binding=4) readonly uniform constBuffer {
ivec4 inputSize; // w h icDiv4 n
ivec4 outputSize; // w h ocDiv4 n
} uConstant;
#define UP_DIV(x, y) (((x)+(y)-1)/(y))
// ow * oh * ocDiv4 on
layout (local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in;
void main() {
// -----------------------------
int outputIndexNHW4 = int(gl_GlobalInvocationID.x);
int outputIndexC8 = int(gl_GlobalInvocationID.y);
int outputC8 = UP_DIV(uConstant.outputSize.z, 2);
int outputW4 = UP_DIV(uConstant.outputSize.x, 4);
if (outputIndexNHW4 >= outputW4 * uConstant.outputSize.y * uConstant.outputSize.w || outputIndexC8 >= outputC8) {
return;
}
int outputIndexW4 = outputIndexNHW4 % outputW4;
int outputIndexNH = outputIndexNHW4 / outputW4;
int outputIndexW0 = outputIndexW4 * 4;
int outputIndexW1 = outputIndexW0 + 1;
int outputIndexW2 = outputIndexW0 + 2;
int outputIndexW3 = outputIndexW0 + 3;
int outputIndexH = outputIndexNH % uConstant.outputSize.y;
int outputIndexN = outputIndexNH / uConstant.outputSize.y;
// -----------------------------
int outputIndexC0 = outputIndexC8 * 2;
int outputIndexC1 = outputIndexC0 + 1;
FLOAT4 resultW0C0 = FLOAT4(texelFetch(uBias, ivec2(outputIndexC0, 0), 0));
FLOAT4 resultW1C0 = resultW0C0;
FLOAT4 resultW2C0 = resultW0C0;
FLOAT4 resultW3C0 = resultW0C0;
FLOAT4 resultW0C1 = FLOAT4(texelFetch(uBias, ivec2(outputIndexC1, 0), 0));
FLOAT4 resultW1C1 = resultW0C1;
FLOAT4 resultW2C1 = resultW0C1;
FLOAT4 resultW3C1 = resultW0C1;
for (int inputIndexC4 = 0; inputIndexC4 < uConstant.inputSize.z; inputIndexC4 ++) {
FLOAT4 inputValueW0 = FLOAT4(texelFetch(uInput, ivec2(outputIndexW0 + inputIndexC4 * uConstant.inputSize.x, outputIndexH + outputIndexN * uConstant.inputSize.y), 0));
FLOAT4 inputValueW1 = FLOAT4(texelFetch(uInput, ivec2(outputIndexW1 + inputIndexC4 * uConstant.inputSize.x, outputIndexH + outputIndexN * uConstant.inputSize.y), 0));
FLOAT4 inputValueW2 = FLOAT4(texelFetch(uInput, ivec2(outputIndexW2 + inputIndexC4 * uConstant.inputSize.x, outputIndexH + outputIndexN * uConstant.inputSize.y), 0));
FLOAT4 inputValueW3 = FLOAT4(texelFetch(uInput, ivec2(outputIndexW3 + inputIndexC4 * uConstant.inputSize.x, outputIndexH + outputIndexN * uConstant.inputSize.y), 0));
int kernelIndexXbase = inputIndexC4 * 4;
FLOAT4 weightC00 = FLOAT4(texelFetch(uKernel, ivec2(kernelIndexXbase + 0, outputIndexC0), 0));
FLOAT4 weightC01 = FLOAT4(texelFetch(uKernel, ivec2(kernelIndexXbase + 1, outputIndexC0), 0));
FLOAT4 weightC02 = FLOAT4(texelFetch(uKernel, ivec2(kernelIndexXbase + 2, outputIndexC0), 0));
FLOAT4 weightC03 = FLOAT4(texelFetch(uKernel, ivec2(kernelIndexXbase + 3, outputIndexC0), 0));
FLOAT4 weightC10 = FLOAT4(texelFetch(uKernel, ivec2(kernelIndexXbase + 0, outputIndexC1), 0));
FLOAT4 weightC11 = FLOAT4(texelFetch(uKernel, ivec2(kernelIndexXbase + 1, outputIndexC1), 0));
FLOAT4 weightC12 = FLOAT4(texelFetch(uKernel, ivec2(kernelIndexXbase + 2, outputIndexC1), 0));
FLOAT4 weightC13 = FLOAT4(texelFetch(uKernel, ivec2(kernelIndexXbase + 3, outputIndexC1), 0));
resultW0C0 += inputValueW0.x * weightC00;
resultW0C0 += inputValueW0.y * weightC01;
resultW0C0 += inputValueW0.z * weightC02;
resultW0C0 += inputValueW0.w * weightC03;
resultW0C1 += inputValueW0.x * weightC10;
resultW0C1 += inputValueW0.y * weightC11;
resultW0C1 += inputValueW0.z * weightC12;
resultW0C1 += inputValueW0.w * weightC13;
resultW1C0 += inputValueW1.x * weightC00;
resultW1C0 += inputValueW1.y * weightC01;
resultW1C0 += inputValueW1.z * weightC02;
resultW1C0 += inputValueW1.w * weightC03;
resultW1C1 += inputValueW1.x * weightC10;
resultW1C1 += inputValueW1.y * weightC11;
resultW1C1 += inputValueW1.z * weightC12;
resultW1C1 += inputValueW1.w * weightC13;
resultW2C0 += inputValueW2.x * weightC00;
resultW2C0 += inputValueW2.y * weightC01;
resultW2C0 += inputValueW2.z * weightC02;
resultW2C0 += inputValueW2.w * weightC03;
resultW2C1 += inputValueW2.x * weightC10;
resultW2C1 += inputValueW2.y * weightC11;
resultW2C1 += inputValueW2.z * weightC12;
resultW2C1 += inputValueW2.w * weightC13;
resultW3C0 += inputValueW3.x * weightC00;
resultW3C0 += inputValueW3.y * weightC01;
resultW3C0 += inputValueW3.z * weightC02;
resultW3C0 += inputValueW3.w * weightC03;
resultW3C1 += inputValueW3.x * weightC10;
resultW3C1 += inputValueW3.y * weightC11;
resultW3C1 += inputValueW3.z * weightC12;
resultW3C1 += inputValueW3.w * weightC13;
}
#if defined(RELU_FP32) || defined(RELU_FP16)
resultW0C0 = FLOAT4(max(resultW0C0, FLOAT4(0)));
resultW0C1 = FLOAT4(max(resultW0C1, FLOAT4(0)));
resultW1C0 = FLOAT4(max(resultW1C0, FLOAT4(0)));
resultW1C1 = FLOAT4(max(resultW1C1, FLOAT4(0)));
resultW2C0 = FLOAT4(max(resultW2C0, FLOAT4(0)));
resultW2C1 = FLOAT4(max(resultW2C1, FLOAT4(0)));
resultW3C0 = FLOAT4(max(resultW3C0, FLOAT4(0)));
resultW3C1 = FLOAT4(max(resultW3C1, FLOAT4(0)));
#endif
#if defined(RELU6_FP32) || defined(RELU6_FP16)
resultW0C0 = FLOAT4(clamp(resultW0C0, FLOAT4(0), FLOAT4(6)));
resultW0C1 = FLOAT4(clamp(resultW0C1, FLOAT4(0), FLOAT4(6)));
resultW1C0 = FLOAT4(clamp(resultW1C0, FLOAT4(0), FLOAT4(6)));
resultW1C1 = FLOAT4(clamp(resultW1C1, FLOAT4(0), FLOAT4(6)));
resultW2C0 = FLOAT4(clamp(resultW2C0, FLOAT4(0), FLOAT4(6)));
resultW2C1 = FLOAT4(clamp(resultW2C1, FLOAT4(0), FLOAT4(6)));
resultW3C0 = FLOAT4(clamp(resultW3C0, FLOAT4(0), FLOAT4(6)));
resultW3C1 = FLOAT4(clamp(resultW3C1, FLOAT4(0), FLOAT4(6)));
#endif
imageStore(uOutput, ivec2(outputIndexW0 + outputIndexC0 * uConstant.outputSize.x, outputIndexH + outputIndexN * uConstant.outputSize.y), resultW0C0);
if (outputIndexW1 < uConstant.outputSize.x) {
imageStore(uOutput, ivec2(outputIndexW1 + outputIndexC0 * uConstant.outputSize.x, outputIndexH + outputIndexN * uConstant.outputSize.y), resultW1C0);
}
if (outputIndexW2 < uConstant.outputSize.x) {
imageStore(uOutput, ivec2(outputIndexW2 + outputIndexC0 * uConstant.outputSize.x, outputIndexH + outputIndexN * uConstant.outputSize.y), resultW2C0);
}
if (outputIndexW3 < uConstant.outputSize.x) {
imageStore(uOutput, ivec2(outputIndexW3 + outputIndexC0 * uConstant.outputSize.x, outputIndexH + outputIndexN * uConstant.outputSize.y), resultW3C0);
}
if (outputIndexC1 < uConstant.outputSize.z) {
imageStore(uOutput, ivec2(outputIndexW0 + outputIndexC1 * uConstant.outputSize.x, outputIndexH + outputIndexN * uConstant.outputSize.y), resultW0C1);
if (outputIndexW1 < uConstant.outputSize.x) {
imageStore(uOutput, ivec2(outputIndexW1 + outputIndexC1 * uConstant.outputSize.x, outputIndexH + outputIndexN * uConstant.outputSize.y), resultW1C1);
}
if (outputIndexW2 < uConstant.outputSize.x) {
imageStore(uOutput, ivec2(outputIndexW2 + outputIndexC1 * uConstant.outputSize.x, outputIndexH + outputIndexN * uConstant.outputSize.y), resultW2C1);
}
if (outputIndexW3 < uConstant.outputSize.x) {
imageStore(uOutput, ivec2(outputIndexW3 + outputIndexC1 * uConstant.outputSize.x, outputIndexH + outputIndexN * uConstant.outputSize.y), resultW3C1);
}
}
return;
}