From bb04055e80aa9de41c8b6361ca238c9b4444ad2a Mon Sep 17 00:00:00 2001 From: nihuini Date: Thu, 28 Feb 2019 20:14:13 +0800 Subject: [PATCH] permute shader --- src/layer/permute.cpp | 159 +++++++++++++++++++++++++ src/layer/permute.h | 12 ++ src/layer/shader/packing_4to1.comp | 4 +- src/layer/shader/permute.comp | 104 ++++++++++++++++ src/layer/shader/permute_pack4to1.comp | 109 +++++++++++++++++ 5 files changed, 386 insertions(+), 2 deletions(-) create mode 100644 src/layer/shader/permute.comp create mode 100644 src/layer/shader/permute_pack4to1.comp diff --git a/src/layer/permute.cpp b/src/layer/permute.cpp index 4a285d2d9..33948d39c 100644 --- a/src/layer/permute.cpp +++ b/src/layer/permute.cpp @@ -22,6 +22,12 @@ Permute::Permute() { one_blob_only = true; support_inplace = false; + support_vulkan = true; + +#if NCNN_VULKAN + pipeline_permute = 0; + pipeline_permute_pack4to1 = 0; +#endif // NCNN_VULKAN } int Permute::load_param(const ParamDict& pd) @@ -196,4 +202,157 @@ int Permute::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) c return 0; } +#if NCNN_VULKAN +int Permute::create_pipeline() +{ + std::vector specializations(1); + specializations[0].i = order_type; + + pipeline_permute = new Pipeline(vkdev); + pipeline_permute->set_optimal_local_size_xyz(); + pipeline_permute->create("permute", specializations, 2, 10); + + // pack4 + { + pipeline_permute_pack4to1 = new Pipeline(vkdev); + pipeline_permute_pack4to1->set_optimal_local_size_xyz(); + pipeline_permute_pack4to1->create("permute_pack4to1", specializations, 2, 10); + } + + return 0; +} + +int Permute::destroy_pipeline() +{ + delete pipeline_permute; + pipeline_permute = 0; + + delete pipeline_permute_pack4to1; + pipeline_permute_pack4to1 = 0; + + return 0; +} + +int Permute::forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& cmd, const Option& opt) const +{ + int w = bottom_blob.w; + int h = bottom_blob.h; + int channels = bottom_blob.c; + size_t elemsize = bottom_blob.elemsize; + int packing = bottom_blob.packing; + + int dims = bottom_blob.dims; + + int out_packing = 1; + size_t out_elemsize = elemsize / packing; + + if (dims == 2) + { + // order_type + // 0 = w h + // 1 = h w + + h = h * packing; + + if (order_type == 0) + { + top_blob.create(w, h, out_elemsize, out_packing, opt.blob_vkallocator, opt.staging_vkallocator); + if (top_blob.empty()) + return -100; + } + else if (order_type == 1) + { + top_blob.create(h, w, out_elemsize, out_packing, opt.blob_vkallocator, opt.staging_vkallocator); + if (top_blob.empty()) + return -100; + } + } + else if (dims == 3) + { + // order_type + // 0 = w h c + // 1 = h w c + // 2 = w c h + // 3 = c w h + // 4 = h c w + // 5 = c h w + + channels = channels * packing; + + if (order_type == 0) + { + top_blob.create(w, h, channels, out_elemsize, out_packing, opt.blob_vkallocator, opt.staging_vkallocator); + if (top_blob.empty()) + return -100; + } + else if (order_type == 1) + { + top_blob.create(h, w, channels, out_elemsize, out_packing, opt.blob_vkallocator, opt.staging_vkallocator); + if (top_blob.empty()) + return -100; + } + else if (order_type == 2) + { + top_blob.create(w, channels, h, out_elemsize, out_packing, opt.blob_vkallocator, opt.staging_vkallocator); + if (top_blob.empty()) + return -100; + } + else if (order_type == 3) + { + top_blob.create(channels, w, h, out_elemsize, out_packing, opt.blob_vkallocator, opt.staging_vkallocator); + if (top_blob.empty()) + return -100; + } + else if (order_type == 4) + { + top_blob.create(h, channels, w, out_elemsize, out_packing, opt.blob_vkallocator, opt.staging_vkallocator); + if (top_blob.empty()) + return -100; + } + else if (order_type == 5) + { + top_blob.create(channels, h, w, out_elemsize, out_packing, opt.blob_vkallocator, opt.staging_vkallocator); + if (top_blob.empty()) + return -100; + } + } + + fprintf(stderr, "%d %d %d\n", top_blob.w, top_blob.h, top_blob.c); + +// fprintf(stderr, "Permute::forward %p %p\n", bottom_blob.buffer(), top_blob.buffer()); + + std::vector bindings(2); + bindings[0] = bottom_blob; + bindings[1] = top_blob; + + std::vector constants(10); + constants[0].i = bottom_blob.dims; + constants[1].i = bottom_blob.w; + constants[2].i = bottom_blob.h; + constants[3].i = bottom_blob.c; + constants[4].i = bottom_blob.cstep; + constants[5].i = top_blob.dims; + constants[6].i = top_blob.w; + constants[7].i = top_blob.h; + constants[8].i = top_blob.c; + constants[9].i = top_blob.cstep; + + // record + cmd.record_prepare_compute_barrier(bottom_blob); + cmd.record_prepare_compute_barrier(top_blob); + + if (packing == 1) + { + cmd.record_pipeline(pipeline_permute, bindings, constants, top_blob); + } + + if (packing == 4) + { + cmd.record_pipeline(pipeline_permute_pack4to1, bindings, constants, bottom_blob); + } + + return 0; +} +#endif // NCNN_VULKAN + } // namespace ncnn diff --git a/src/layer/permute.h b/src/layer/permute.h index 963aa5f20..328c1b874 100644 --- a/src/layer/permute.h +++ b/src/layer/permute.h @@ -28,8 +28,20 @@ public: virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const; +#if NCNN_VULKAN + virtual int create_pipeline(); + virtual int destroy_pipeline(); + + virtual int forward(const VkMat& bottom_blob, VkMat& top_blob, VkCompute& cmd, const Option& opt) const; +#endif // NCNN_VULKAN + public: int order_type; + +#if NCNN_VULKAN + Pipeline* pipeline_permute; + Pipeline* pipeline_permute_pack4to1; +#endif // NCNN_VULKAN }; } // namespace ncnn diff --git a/src/layer/shader/packing_4to1.comp b/src/layer/shader/packing_4to1.comp index b7968a945..ce79facbd 100644 --- a/src/layer/shader/packing_4to1.comp +++ b/src/layer/shader/packing_4to1.comp @@ -47,9 +47,9 @@ void main() ivec4 z4 = ivec4(gz * 4) + ivec4(0, 1, 2, 3); - ivec4 v_offset = z4 * p.cstep + ivec4(gy * p.w + gx); + ivec4 v_offset = z4 * p.outcstep + ivec4(gy * p.outw + gx); - vec4 v = bottom_blob_data[gz * p.outcstep + gy * p.outw + gx]; + vec4 v = bottom_blob_data[gz * p.cstep + gy * p.w + gx]; top_blob_data[v_offset.r] = v.r; top_blob_data[v_offset.g] = v.g; diff --git a/src/layer/shader/permute.comp b/src/layer/shader/permute.comp new file mode 100644 index 000000000..fc3672758 --- /dev/null +++ b/src/layer/shader/permute.comp @@ -0,0 +1,104 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#version 450 + +layout (constant_id = 0) const int order_type = 0; + +layout (local_size_x_id = 233) in; +layout (local_size_y_id = 234) in; +layout (local_size_z_id = 235) in; + +layout (binding = 0) readonly buffer bottom_blob { float bottom_blob_data[]; }; +layout (binding = 1) writeonly buffer top_blob { float top_blob_data[]; }; + +layout (push_constant) uniform parameter +{ + int dims; + int w; + int h; + int c; + int cstep; + + int outdims; + int outw; + int outh; + int outc; + int outcstep; +} p; + +void main() +{ + int gx = int(gl_GlobalInvocationID.x); + int gy = int(gl_GlobalInvocationID.y); + int gz = int(gl_GlobalInvocationID.z); + + if (gx >= p.outw || gy >= p.outh || gz >= p.outc) + return; + + int v_offset; + + if (p.dims == 2) + { + // order_type + // 0 = w h + // 1 = h w + + if (order_type == 0) + { + v_offset = gy * p.w + gx; + } + if (order_type == 1) + { + v_offset = gx * p.w + gy; + } + } + else if (p.dims == 3) + { + // order_type + // 0 = w h c + // 1 = h w c + // 2 = w c h + // 3 = c w h + // 4 = h c w + // 5 = c h w + + if (order_type == 0) + { + v_offset = gz * p.cstep + gy * p.w + gx; + } + if (order_type == 1) + { + v_offset = gz * p.cstep + gx * p.w + gy; + } + if (order_type == 2) + { + v_offset = gy * p.cstep + gz * p.w + gx; + } + if (order_type == 3) + { + v_offset = gx * p.cstep + gz * p.w + gy; + } + if (order_type == 4) + { + v_offset = gy * p.cstep + gx * p.w + gz; + } + if (order_type == 5) + { + v_offset = gx * p.cstep + gy * p.w + gz; + } + } + + top_blob_data[gz * p.outcstep + gy * p.outw + gx] = bottom_blob_data[v_offset]; +} diff --git a/src/layer/shader/permute_pack4to1.comp b/src/layer/shader/permute_pack4to1.comp new file mode 100644 index 000000000..d04a74c99 --- /dev/null +++ b/src/layer/shader/permute_pack4to1.comp @@ -0,0 +1,109 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#version 450 + +layout (constant_id = 0) const int order_type = 0; + +layout (local_size_x_id = 233) in; +layout (local_size_y_id = 234) in; +layout (local_size_z_id = 235) in; + +layout (binding = 0) readonly buffer bottom_blob { vec4 bottom_blob_data[]; }; +layout (binding = 1) writeonly buffer top_blob { float top_blob_data[]; }; + +layout (push_constant) uniform parameter +{ + int dims; + int w; + int h; + int c; + int cstep; + + int outdims; + int outw; + int outh; + int outc; + int outcstep; +} p; + +void main() +{ + int gx = int(gl_GlobalInvocationID.x); + int gy = int(gl_GlobalInvocationID.y); + int gz = int(gl_GlobalInvocationID.z); + + if (gx >= p.w || gy >= p.h || gz >= p.c) + return; + + ivec4 v_offset; + + if (p.dims == 2) + { + // order_type + // 0 = w h + // 1 = h w + + if (order_type == 0) + { + v_offset = ivec4((gy * 4) * p.outw + gx) + ivec4(0, 1, 2, 3) * p.outw; + } + if (order_type == 1) + { + v_offset = ivec4(gx * p.outw + gy) + ivec4(0, 1, 2, 3); + } + } + else if (p.dims == 3) + { + // order_type + // 0 = w h c + // 1 = h w c + // 2 = w c h + // 3 = c w h + // 4 = h c w + // 5 = c h w + + if (order_type == 0) + { + v_offset = ivec4((gz * 4) * p.outcstep + gy * p.outw + gx) + ivec4(0, 1, 2, 3) * p.outcstep; + } + if (order_type == 1) + { + v_offset = ivec4((gz * 4) * p.outcstep + gx * p.outw + gy) + ivec4(0, 1, 2, 3) * p.outcstep; + } + if (order_type == 2) + { + v_offset = ivec4(gy * p.outcstep + (gz * 4) * p.outw + gx) + ivec4(0, 1, 2, 3) * p.outw; + } + if (order_type == 3) + { + v_offset = ivec4(gy * p.outcstep + gx * p.outw + gz * 4) + ivec4(0, 1, 2, 3); + } + if (order_type == 4) + { + v_offset = ivec4(gx * p.outcstep + (gz * 4) * p.outw + gy) + ivec4(0, 1, 2, 3) * p.outw; + } + if (order_type == 5) + { + v_offset = ivec4(gx * p.outcstep + gy * p.outw + gz * 4) + ivec4(0, 1, 2, 3); + } + } + + vec4 v = bottom_blob_data[gz * p.cstep + gy * p.w + gx]; + + top_blob_data[v_offset.r] = v.r; + top_blob_data[v_offset.g] = v.g; + top_blob_data[v_offset.b] = v.b; + top_blob_data[v_offset.a] = v.a; +}