1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4 //
5 // Copyright (C) 2018, Intel Corporation, all rights reserved.
6 // Third party copyrights are property of their respective owners.
7 
8 #include "../../precomp.hpp"
9 #include <limits>
10 #include "common.hpp"
11 #include "internal.hpp"
12 #include "../include/op_prior_box.hpp"
13 
14 namespace cv { namespace dnn { namespace vkcom {
15 
16 #ifdef HAVE_VULKAN
17 
18 #define LOCAL_SZ_X 256
19 struct PriorBoxParam {
20       int global_size;
21       int nthreads;
22       float step_x;
23       float step_y;
24       int offsets_x_size;
25       int width_size;
26       int layer_w;
27       int image_h;
28       int image_w;
29       int clip;
30       int variance_off;
31 };
32 
OpPriorBox(float step_x,float step_y,bool clip,int num_priors,std::vector<float> & variance,std::vector<float> & offsets_x,std::vector<float> & offsets_y,std::vector<float> & box_widths,std::vector<float> & box_heights)33 OpPriorBox::OpPriorBox(float step_x,
34                        float step_y,
35                        bool clip,
36                        int num_priors,
37                        std::vector<float>& variance,
38                        std::vector<float>& offsets_x,
39                        std::vector<float>& offsets_y,
40                        std::vector<float>& box_widths,
41                        std::vector<float>& box_heights)
42 {
43     step_x_ = step_x;
44     step_y_ = step_y;
45     clip_ = clip;
46     num_priors_ = num_priors;
47     variance_ = variance;
48     offsets_x_ = offsets_x;
49     offsets_y_ = offsets_y;
50     box_widths_ = box_widths;
51     box_heights_ = box_heights;
52     type_ = "PriorBox";
53 #define BUFFER_NUM 6
54     OpBase::initVulkanThing(BUFFER_NUM);
55 }
56 
reshapeOutTensor(std::vector<Tensor * > & ins,Tensor & out)57 void OpPriorBox::reshapeOutTensor(std::vector<Tensor *>& ins, Tensor& out)
58 {
59     assert(!ins.empty());
60 
61     Shape in_shape = ins[0]->getShape();
62     int layer_h = in_shape[kShapeIdxHeight];
63     int layer_w = in_shape[kShapeIdxWidth];
64     int out_num = 1;
65     int out_channel = 2;
66     Shape out_shape = {out_num, out_channel, layer_h * layer_w * num_priors_ * 4};
67     out.reshape(NULL, out_shape);
68 }
69 
forward(std::vector<Tensor> & ins,std::vector<Tensor> & blobs,std::vector<Tensor> & outs)70 bool OpPriorBox::forward(std::vector<Tensor>& ins,
71                          std::vector<Tensor>& blobs,
72                          std::vector<Tensor>& outs)
73 {
74     return forward(ins, outs[0]);
75 }
76 
forward(std::vector<Tensor> & ins,Tensor & out)77 bool OpPriorBox::forward(std::vector<Tensor>& ins, Tensor& out)
78 {
79     assert(ins.size() == 2);
80     Shape in_shape = ins[0].getShape();
81     Shape img_shape = ins[1].getShape();
82 
83     in_h_ = in_shape[kShapeIdxHeight];
84     in_w_ = in_shape[kShapeIdxWidth];
85     img_h_ = img_shape[kShapeIdxHeight];
86     img_w_ = img_shape[kShapeIdxWidth];
87     out_channel_ = out.dimSize(1);
88     out_channel_size_ = out.dimSize(2);
89     nthreads_ = in_h_ * in_w_;
90     global_size_ = alignSize(nthreads_, LOCAL_SZ_X);
91 
92     if (pipeline_ == VK_NULL_HANDLE)
93     {
94         createShaderModule(prior_box_spv, sizeof(prior_box_spv));
95         createPipeline(sizeof(PriorBoxParam));
96         computeGroupCount();
97     }
98 
99     std::vector<int>shape;
100     shape.push_back(offsets_x_.size());
101     tensor_offsets_x_.reshape((const char*)offsets_x_.data(), shape);
102     tensor_offsets_y_.reshape((const char*)offsets_y_.data(), shape);
103 
104     shape[0] = box_widths_.size();
105     tensor_widths_.reshape((const char*)box_widths_.data(), shape);
106     tensor_heights_.reshape((const char*)box_heights_.data(), shape);
107 
108     float variance[4] = {variance_[0], variance_[0], variance_[0], variance_[0]};
109     if (variance_.size() > 1)
110     {
111         assert(variance_.size() == 4);
112         for (int i = 1; i < variance_.size(); i++)
113             variance[i] = variance_[i];
114     }
115     shape[0] = 4;
116     tensor_variance_.reshape((const char*)variance, shape);
117 
118     bindTensor(device_, tensor_offsets_x_,  0, descriptor_set_);
119     bindTensor(device_, tensor_offsets_y_, 1, descriptor_set_);
120     bindTensor(device_, tensor_widths_,  2, descriptor_set_);
121     bindTensor(device_, tensor_heights_, 3, descriptor_set_);
122     bindTensor(device_, tensor_variance_, 4, descriptor_set_);
123     bindTensor(device_, out, 5, descriptor_set_);
124 
125     PriorBoxParam param = {global_size_,
126                            nthreads_,
127                            step_x_,
128                            step_y_,
129                            (int)offsets_x_.size(),
130                            (int)box_widths_.size(),
131                            in_w_,
132                            img_h_,
133                            img_w_,
134                            clip_ ? 1 : 0,
135                            out_channel_size_ / 4};
136     recordCommandBuffer((void *)&param, sizeof(PriorBoxParam));
137     runCommandBuffer();
138     return true;
139 }
140 
computeGroupCount()141 bool OpPriorBox::computeGroupCount()
142 {
143     group_x_ = global_size_ / LOCAL_SZ_X;
144     group_y_ = 1;
145     group_z_ = 1;
146     return true;
147 }
148 
149 #endif // HAVE_VULKAN
150 
151 }}} // namespace cv::dnn::vkcom
152