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

462 lines
19 KiB
Common Lisp

#ifdef MNN_SUPPORT_FP16
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
#endif
#define GLOBAL_SIZE_3_DIMS \
__private const int global_size_dim0, __private const int global_size_dim1, __private const int global_size_dim2,
#define DEAL_NON_UNIFORM_DIM3(input1, input2, input3) \
if (input1 >= global_size_dim0 || input2 >= global_size_dim1 || input3 >= global_size_dim2) { \
return; \
}
__kernel void pooling_c4_c4(GLOBAL_SIZE_3_DIMS __global const FLOAT *input,
__private const int2 input_shape,
__private const int2 output_shape,
__private const int2 pad_shape,
__global FLOAT *output,
__global FLOAT *rediceOutput,
__private const int channel,
__private const int batch,
__private const int in_channel_block,
__private const int out_channel_block,
__private const int input_pad_left,
__private const int input_pad_right,
__private const int output_pad_left,
__private const int output_pad_right) {
const int ow_idx = get_global_id(0);
const int b_oh_idx = get_global_id(1);
const int c_idx = get_global_id(2);
DEAL_NON_UNIFORM_DIM3(ow_idx, b_oh_idx, c_idx);
const int b_idx = b_oh_idx / output_shape.x;
const int oh_idx = b_oh_idx % output_shape.x;
const int iw_start = mad24(ow_idx, STRIDE_X, -pad_shape.y);
const int ih_start = mad24(oh_idx, STRIDE_Y, -pad_shape.x);
#ifdef POOL_AVG
COMPUTE_FLOAT4 result = (COMPUTE_FLOAT4)(0);
const int inp_offset = (((b_idx+c_idx*batch)*input_shape.x+ih_start)*input_shape.y+iw_start+input_pad_left)*4;
#ifdef COUNT_INCLUDE_PADDING
int total_count = (min(ih_start + KERNEL_Y, input_shape.x + pad_shape.x) - ih_start) * (min(iw_start + KERNEL_X, input_shape.y + pad_shape.y) - iw_start);
#else
int total_count = 0;
#endif
for(int kh=0; kh<KERNEL_Y; kh++) {
int ih_cur = ih_start + kh;
if(ih_cur < 0 || ih_cur >= input_shape.x) {
continue;
}
for(int kw=0; kw<KERNEL_X; kw++) {
int iw_cur = iw_start + kw;
if(iw_cur < 0 || iw_cur >= input_shape.y) {
continue;
}
COMPUTE_FLOAT4 inp_data = CONVERT_COMPUTE_FLOAT4(vload4(0, input+inp_offset+(kh*input_shape.y+kw)*4));
result += inp_data;
#ifndef COUNT_INCLUDE_PADDING
total_count++;
#endif
}
}
result = result / (COMPUTE_FLOAT4)(1.0*total_count);
#else
COMPUTE_FLOAT4 result = (COMPUTE_FLOAT4)(-FLT_MAX);
#if RETURN_REDICE
int4 redice = (int4)0;
#endif
const int inp_offset = (((b_idx+c_idx*batch)*input_shape.x+ih_start)*input_shape.y+iw_start+input_pad_left)*4;
for(int kh=0; kh<KERNEL_Y; kh++) {
int ih_cur = ih_start + kh;
if(ih_cur < 0 || ih_cur >= input_shape.x) {
continue;
}
for(int kw=0; kw<KERNEL_X; kw++) {
int iw_cur = iw_start + kw;
if(iw_cur < 0 || iw_cur >= input_shape.y) {
continue;
}
COMPUTE_FLOAT4 inp_data = CONVERT_COMPUTE_FLOAT4(vload4(0, input+inp_offset+(kh*input_shape.y+kw)*4));
#if RETURN_REDICE
redice = inp_data > result ? (int4)((ih_start + kh) * input_shape.y + iw_start + kw) : redice;
#endif
result = fmax(result, inp_data);
}
}
#endif
const int out_offset = (((b_idx + c_idx*batch)*output_shape.x + oh_idx)* output_shape.y + ow_idx + output_pad_left)*4;
vstore4(CONVERT_FLOAT4(result), 0, output+out_offset);
#if RETURN_REDICE
vstore4(CONVERT_FLOAT4(redice), 0, rediceOutput+(((b_idx + c_idx*batch)*output_shape.x + oh_idx)* output_shape.y + ow_idx)*4);
#endif
}
__kernel void pooling_c4_c16(GLOBAL_SIZE_3_DIMS __global const FLOAT *input,
__private const int2 input_shape,
__private const int2 output_shape,
__private const int2 pad_shape,
__global FLOAT *output,
__global FLOAT *rediceOutput,
__private const int channel,
__private const int batch,
__private const int in_channel_block,
__private const int out_channel_block,
__private const int input_pad_left,
__private const int input_pad_right,
__private const int output_pad_left,
__private const int output_pad_right) {
const int ow_idx = get_global_id(0);
const int b_oh_idx = get_global_id(1);
const int c_idx = get_global_id(2);
DEAL_NON_UNIFORM_DIM3(ow_idx, b_oh_idx, c_idx);
const int b_idx = b_oh_idx / output_shape.x;
const int oh_idx = b_oh_idx % output_shape.x;
const int iw_start = mad24(ow_idx, STRIDE_X, -pad_shape.y);
const int ih_start = mad24(oh_idx, STRIDE_Y, -pad_shape.x);
const int dst_width = output_shape.y + output_pad_left + output_pad_right;
#ifdef POOL_AVG
COMPUTE_FLOAT4 result = (COMPUTE_FLOAT4)(0);
const int inp_offset = (((b_idx+c_idx*batch)*input_shape.x+ih_start)*input_shape.y+iw_start+input_pad_left)*4;
#ifdef COUNT_INCLUDE_PADDING
int total_count = (min(ih_start + KERNEL_Y, input_shape.x + pad_shape.x) - ih_start) * (min(iw_start + KERNEL_X, input_shape.y + pad_shape.y) - iw_start);
#else
int total_count = 0;
#endif
for(int kh=0; kh<KERNEL_Y; kh++) {
int ih_cur = ih_start + kh;
if(ih_cur < 0 || ih_cur >= input_shape.x) {
continue;
}
for(int kw=0; kw<KERNEL_X; kw++) {
int iw_cur = iw_start + kw;
if(iw_cur < 0 || iw_cur >= input_shape.y) {
continue;
}
COMPUTE_FLOAT4 inp_data = CONVERT_COMPUTE_FLOAT4(vload4(0, input+inp_offset+(kh*input_shape.y+kw)*4));
result += inp_data;
#ifndef COUNT_INCLUDE_PADDING
total_count++;
#endif
}
}
result = result / (COMPUTE_FLOAT4)(1.0*total_count);
#else
COMPUTE_FLOAT4 result = (COMPUTE_FLOAT4)(-FLT_MAX);
#if RETURN_REDICE
int4 redice = (int4)0;
#endif
const int inp_offset = (((b_idx+c_idx*batch)*input_shape.x+ih_start)*input_shape.y+iw_start+input_pad_left)*4;
for(int kh=0; kh<KERNEL_Y; kh++) {
int ih_cur = ih_start + kh;
if(ih_cur < 0 || ih_cur >= input_shape.x) {
continue;
}
for(int kw=0; kw<KERNEL_X; kw++) {
int iw_cur = iw_start + kw;
if(iw_cur < 0 || iw_cur >= input_shape.y) {
continue;
}
COMPUTE_FLOAT4 inp_data = CONVERT_COMPUTE_FLOAT4(vload4(0, input+inp_offset+(kh*input_shape.y+kw)*4));
#if RETURN_REDICE
redice = inp_data > result ? (int4)((ih_start + kh) * input_shape.y + iw_start + kw) : redice;
#endif
result = fmax(result, inp_data);
}
}
#endif
const int c_left = (c_idx % 4) * 4;
const int out_offset = (((b_idx*out_channel_block + c_idx/4)*output_shape.x + oh_idx)* dst_width + ow_idx + output_pad_left)*16 + c_left;
vstore4(CONVERT_FLOAT4(result), 0, output+out_offset);
#if RETURN_REDICE
vstore4(CONVERT_FLOAT4(redice), 0, rediceOutput+(((b_idx*out_channel_block + c_idx)*output_shape.x + oh_idx)* output_shape.y + ow_idx)*4);
#endif
if(ow_idx == 0){
int pad_offset = (((b_idx*out_channel_block + c_idx/4)*output_shape.x + oh_idx)* dst_width + 0)*16 + c_left;
for(int i = 0; i < output_pad_left; ++i){
vstore4((FLOAT4)0, 0, output + pad_offset + i * 16);
}
pad_offset += (output_shape.y + output_pad_left) * 16;
for(int i = 0; i < output_pad_right; ++i){
vstore4((FLOAT4)0, 0, output + pad_offset + i * 16);
}
}
}
__attribute__((intel_reqd_sub_group_size(16)))
__kernel void pooling_c16_c16(GLOBAL_SIZE_3_DIMS __global const FLOAT *input,
__private const int2 input_shape,
__private const int2 output_shape,
__private const int2 pad_shape,
__global FLOAT *output,
__global FLOAT *rediceOutput,
__private const int channel,
__private const int batch,
__private const int in_channel_block,
__private const int out_channel_block,
__private const int input_pad_left,
__private const int input_pad_right,
__private const int output_pad_left,
__private const int output_pad_right) {
const int ow_idx = get_global_id(1) << 3;
const int b_oh_idx = get_global_id(2);
const int c_idx = get_group_id(0);
const int sglid = get_sub_group_local_id();
const int b_idx = b_oh_idx / output_shape.x;
const int oh_idx = b_oh_idx % output_shape.x;
const int iw_start = mad24(ow_idx, STRIDE_X, -pad_shape.y);
const int ih_start = mad24(oh_idx, STRIDE_Y, -pad_shape.x);
const int src_width = input_shape.y + input_pad_left + input_pad_right;
const int dst_width = output_shape.y + output_pad_left + output_pad_right;
#ifdef POOL_AVG
COMPUTE_FLOAT8 result = (COMPUTE_FLOAT8)(0);
COMPUTE_FLOAT8 w_start = (COMPUTE_FLOAT8)(iw_start, iw_start + STRIDE_X, iw_start + STRIDE_X * 2, iw_start + STRIDE_X * 3, iw_start + STRIDE_X * 4, iw_start + STRIDE_X * 5, iw_start + STRIDE_X * 6, iw_start + STRIDE_X * 7);
#ifdef COUNT_INCLUDE_PADDING
COMPUTE_FLOAT8 w_size = fmin(w_start + KERNEL_X, input_shape.y + pad_shape.y) - w_start;
COMPUTE_FLOAT8 total_count = (COMPUTE_FLOAT8)(min(ih_start + KERNEL_Y, input_shape.x + pad_shape.x) - ih_start) * w_size;
#else
w_start = fmax(w_start, (COMPUTE_FLOAT8)0);
COMPUTE_FLOAT8 w_end = fmin(w_start + KERNEL_X, (COMPUTE_FLOAT8)input_shape.y);
float h_start = fmax((float)ih_start, 0);
float h_end = fmin(h_start + KERNEL_Y, (float)input_shape.x);
COMPUTE_FLOAT8 total_count = (w_end - w_start) * (COMPUTE_FLOAT8)(h_end - h_start);
#endif
#else
COMPUTE_FLOAT8 result = (COMPUTE_FLOAT8)(-FLT_MAX);
#if RETURN_REDICE
int8 redice = (int8)0;
#endif
#endif
const int inp_offset = mul24(mad24(mad24(mad24(b_idx,in_channel_block,c_idx),input_shape.x,ih_start),src_width,iw_start+input_pad_left),16);
for(int kh=0; kh<KERNEL_Y; kh++) {
int ih_cur = ih_start + kh;
if(ih_cur < 0 || ih_cur >= input_shape.x) {
continue;
}
FLOAT line_cache[INPUT_LINE_SIZE];
for (int i = 0; i < INPUT_LINE_SIZE; i++) {
if ((iw_start + i) >= 0 && (iw_start + i) < input_shape.y){
#ifdef MNN_SUPPORT_FP16
line_cache[i] = as_half(intel_sub_group_block_read_us((__global ushort*)(input + inp_offset + mul24(mad24(kh,src_width,i),16))));
#else
line_cache[i] = as_float(intel_sub_group_block_read((__global uint*)(input + inp_offset + mul24(mad24(kh,src_width,i),16))));
#endif
} else{
#ifdef POOL_AVG
line_cache[i] = 0;
#else
line_cache[i] = (COMPUTE_FLOAT)(-FLT_MAX);
#endif
}
}
for(int kw=0; kw<KERNEL_X; kw++) {
COMPUTE_FLOAT8 src;
__attribute__((opencl_unroll_hint(8)))
for (int i = 0; i < 8; i++) {
src[i] = line_cache[kw + STRIDE_X*i];
}
#ifdef POOL_AVG
result += src;
#else
#if RETURN_REDICE
redice = src > result ? (int8)((ih_start + kh) * input_shape.y + iw_start + kw) : redice;
#endif
result = fmax(result, src);
#endif
}
}
#ifdef POOL_AVG
result = result / total_count;
#endif
if(ow_idx == 0){
int pad_offset = (((b_idx*out_channel_block + c_idx)*output_shape.x + oh_idx)* dst_width + 0)*16 + sglid;
for(int i = 0; i < output_pad_left; ++i){
output[pad_offset+i*16] = 0;
}
pad_offset += (output_shape.y + output_pad_left) * 16;
for(int i = 0; i < output_pad_right; ++i){
output[pad_offset+i*16] = 0;
}
}
const int out_offset = (((b_idx*out_channel_block + c_idx)*output_shape.x + oh_idx)* dst_width + ow_idx + output_pad_left)*16;
#if OUTPUT_LEFTOVERS
if ((c_idx+1)*16 >= channel) {
for (int i = 0; i < 8; i++) {
if ((c_idx*16 + sglid < channel) && (ow_idx + i) < output_shape.y)
output[out_offset + i * 16 + sglid] = result[i];
}
}
else
#endif
{
if (ow_idx + 8 <= output_shape.y) {
#ifdef MNN_SUPPORT_FP16
intel_sub_group_block_write_us8((__global ushort*)(output + out_offset), as_ushort8(CONVERT_FLOAT8(result)));
#else
intel_sub_group_block_write8((__global uint*)(output + out_offset), as_uint8(CONVERT_FLOAT8(result)));
#endif
}else{
for (int i = 0; i < output_shape.y % 8; i++) {
output[out_offset + i * 16 + sglid] = result[i];
}
}
}
#ifdef RETURN_REDICE
const uint lid_x = sglid % 4;
const uint lid_y = sglid / 4;
const int width_height = output_shape.y * output_shape.x * 4;
const int redice_offset = (((b_idx*out_channel_block + c_idx * 4)*output_shape.x + oh_idx)* output_shape.y + ow_idx)*4;
#if OUTPUT_LEFTOVERS
if ((c_idx+1)*16 >= channel) {
for (int i = 0; i < 8; i++) {
if ((c_idx*16 + lid_y * 4 + lid_x < channel) && (ow_idx + i) < output_shape.y)
rediceOutput[redice_offset + lid_y * width_height + i * 4 + lid_x] = redice[i];
}
}
else
#endif
{
for (int i = 0; i < 8 && (ow_idx + i) < output_shape.y; i++) {
rediceOutput[redice_offset + lid_y * width_height + i * 4 + lid_x] = redice[i];
}
}
#endif
}
__attribute__((intel_reqd_sub_group_size(16)))
__kernel void pooling_c16_c4(GLOBAL_SIZE_3_DIMS __global const FLOAT *input,
__private const int2 input_shape,
__private const int2 output_shape,
__private const int2 pad_shape,
__global FLOAT *output,
__global FLOAT *rediceOutput,
__private const int channel,
__private const int batch,
__private const int in_channel_block,
__private const int out_channel_block,
__private const int input_pad_left,
__private const int input_pad_right,
__private const int output_pad_left,
__private const int output_pad_right) {
const int ow_idx = get_global_id(1) << 3;
const int b_oh_idx = get_global_id(2);
const int c_idx = get_group_id(0);
const int sglid = get_sub_group_local_id();
const int b_idx = b_oh_idx / output_shape.x;
const int oh_idx = b_oh_idx % output_shape.x;
const int iw_start = mad24(ow_idx, STRIDE_X, -pad_shape.y);
const int ih_start = mad24(oh_idx, STRIDE_Y, -pad_shape.x);
const int src_width = input_shape.y + input_pad_left + input_pad_right;
#ifdef POOL_AVG
COMPUTE_FLOAT8 result = (COMPUTE_FLOAT8)(0);
COMPUTE_FLOAT8 w_start = (COMPUTE_FLOAT8)(iw_start, iw_start + STRIDE_X, iw_start + STRIDE_X * 2, iw_start + STRIDE_X * 3, iw_start + STRIDE_X * 4, iw_start + STRIDE_X * 5, iw_start + STRIDE_X * 6, iw_start + STRIDE_X * 7);
#ifdef COUNT_INCLUDE_PADDING
COMPUTE_FLOAT8 w_size = fmin(w_start + KERNEL_X, input_shape.y + pad_shape.y) - w_start;
COMPUTE_FLOAT8 total_count = (COMPUTE_FLOAT8)(min(ih_start + KERNEL_Y, input_shape.x + pad_shape.x) - ih_start) * w_size;
#else
w_start = fmax(w_start, (COMPUTE_FLOAT8)0);
COMPUTE_FLOAT8 w_end = fmin(w_start + KERNEL_X, (COMPUTE_FLOAT8)input_shape.y);
float h_start = fmax((float)ih_start, 0);
float h_end = fmin(h_start + KERNEL_Y, (float)input_shape.x);
COMPUTE_FLOAT8 total_count = (w_end - w_start) * (COMPUTE_FLOAT8)(h_end - h_start);
#endif
#else
COMPUTE_FLOAT8 result = (COMPUTE_FLOAT8)(-FLT_MAX);
#if RETURN_REDICE
int8 redice = (int8)0;
#endif
#endif
const int inp_offset = mul24(mad24(mad24(mad24(b_idx,in_channel_block,c_idx),input_shape.x,ih_start),src_width,iw_start+input_pad_left),16);
for(int kh=0; kh<KERNEL_Y; kh++) {
int ih_cur = ih_start + kh;
if(ih_cur < 0 || ih_cur >= input_shape.x) {
continue;
}
FLOAT line_cache[INPUT_LINE_SIZE];
for (int i = 0; i < INPUT_LINE_SIZE; i++) {
if ((iw_start + i) >= 0 && (iw_start + i) < input_shape.y){
#ifdef MNN_SUPPORT_FP16
line_cache[i] = as_half(intel_sub_group_block_read_us((__global ushort*)(input + inp_offset + mul24(mad24(kh,src_width,i),16))));
#else
line_cache[i] = as_float(intel_sub_group_block_read((__global uint*)(input + inp_offset + mul24(mad24(kh,src_width,i),16))));
#endif
} else{
#ifdef POOL_AVG
line_cache[i] = 0;
#else
line_cache[i] = (FLOAT)(-FLT_MAX);
#endif
}
}
for(int kw=0; kw<KERNEL_X; kw++) {
COMPUTE_FLOAT8 src;
__attribute__((opencl_unroll_hint(8)))
for (int i = 0; i < 8; i++) {
src[i] = line_cache[kw + STRIDE_X*i];
}
#ifdef POOL_AVG
result += src;
#else
#if RETURN_REDICE
redice = src > result ? (int8)((ih_start + kh) * input_shape.y + iw_start + kw) : redice;
#endif
result = fmax(result, src);
#endif
}
}
#ifdef POOL_AVG
result = result / total_count;
#endif
const uint lid_x = sglid % 4;
const uint lid_y = sglid / 4;
const int out_offset = (((b_idx + c_idx * 4 * batch)*output_shape.x + oh_idx)* output_shape.y + ow_idx + output_pad_left)*4;
const int batch_width_height = batch * output_shape.y * output_shape.x * 4;
#if RETURN_REDICE
const int redice_offset = (((b_idx + c_idx * 4 * batch)*output_shape.x + oh_idx)* output_shape.y + ow_idx)*4;
#endif
#if OUTPUT_LEFTOVERS
if ((c_idx+1)*16 >= channel) {
for (int i = 0; i < 8; i++) {
if ((c_idx*16 + lid_y * 4 + lid_x < channel) && (ow_idx + i) < output_shape.y)
output[out_offset + lid_y * batch_width_height + i * 4 + lid_x] = result[i];
#if RETURN_REDICE
rediceOutput[redice_offset + lid_y * batch_width_height + i * 4 + lid_x] = redice[i];
#endif
}
}
else
#endif
{
for (int i = 0; i < 8 && (ow_idx + i) < output_shape.y; i++) {
output[out_offset + lid_y * batch_width_height + i * 4 + lid_x] = result[i];
#if RETURN_REDICE
rediceOutput[redice_offset + lid_y * batch_width_height + i * 4 + lid_x] = redice[i];
#endif
}
}
}