Fixed calc_output_scale with NO_OUTPUT_SCALE flag set.
[profile/ivi/opencv.git] / samples / gpu / driver_api_stereo_multi.cpp
1 /* This sample demonstrates working on one piece of data using two GPUs.
2    It splits input into two parts and processes them separately on different
3    GPUs. */
4
5 // Disable some warnings which are caused with CUDA headers
6 #if defined(_MSC_VER)
7 #pragma warning(disable: 4201 4408 4100)
8 #endif
9
10 #include <iostream>
11 #include "cvconfig.h"
12 #include "opencv2/core/core.hpp"
13 #include "opencv2/highgui/highgui.hpp"
14 #include "opencv2/cudastereo.hpp"
15
16 #ifdef HAVE_TBB
17 #  include "tbb/tbb_stddef.h"
18 #  if TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202
19 #    include "tbb/tbb.h"
20 #    include "tbb/task.h"
21 #    undef min
22 #    undef max
23 #  else
24 #    undef HAVE_TBB
25 #  endif
26 #endif
27
28 #if !defined(HAVE_CUDA) || !defined(HAVE_TBB) || defined(__arm__)
29
30 int main()
31 {
32 #if !defined(HAVE_CUDA)
33     std::cout << "CUDA support is required (CMake key 'WITH_CUDA' must be true).\n";
34 #endif
35
36 #if !defined(HAVE_TBB)
37     std::cout << "TBB support is required (CMake key 'WITH_TBB' must be true).\n";
38 #endif
39
40 #if defined(__arm__)
41     std::cout << "Unsupported for ARM CUDA library." << std::endl;
42 #endif
43
44     return 0;
45 }
46
47 #else
48
49 #include <cuda.h>
50 #include <cuda_runtime.h>
51
52 using namespace std;
53 using namespace cv;
54 using namespace cv::cuda;
55
56 struct Worker { void operator()(int device_id) const; };
57 void destroyContexts();
58
59 #define safeCall(expr) safeCall_(expr, #expr, __FILE__, __LINE__)
60 inline void safeCall_(int code, const char* expr, const char* file, int line)
61 {
62     if (code != CUDA_SUCCESS)
63     {
64         std::cout << "CUDA driver API error: code " << code << ", expr " << expr
65             << ", file " << file << ", line " << line << endl;
66         destroyContexts();
67         exit(-1);
68     }
69 }
70
71 // Each GPU is associated with its own context
72 CUcontext contexts[2];
73
74 void inline contextOn(int id)
75 {
76     safeCall(cuCtxPushCurrent(contexts[id]));
77 }
78
79 void inline contextOff()
80 {
81     CUcontext prev_context;
82     safeCall(cuCtxPopCurrent(&prev_context));
83 }
84
85 // GPUs data
86 GpuMat d_left[2];
87 GpuMat d_right[2];
88 Ptr<cuda::StereoBM> bm[2];
89 GpuMat d_result[2];
90
91 static void printHelp()
92 {
93     std::cout << "Usage: driver_api_stereo_multi_gpu --left <left_image> --right <right_image>\n";
94 }
95
96 int main(int argc, char** argv)
97 {
98     if (argc < 5)
99     {
100         printHelp();
101         return -1;
102     }
103
104     int num_devices = getCudaEnabledDeviceCount();
105     if (num_devices < 2)
106     {
107         std::cout << "Two or more GPUs are required\n";
108         return -1;
109     }
110
111     for (int i = 0; i < num_devices; ++i)
112     {
113         cv::cuda::printShortCudaDeviceInfo(i);
114
115         DeviceInfo dev_info(i);
116         if (!dev_info.isCompatible())
117         {
118             std::cout << "GPU module isn't built for GPU #" << i << " ("
119                  << dev_info.name() << ", CC " << dev_info.majorVersion()
120                  << dev_info.minorVersion() << "\n";
121             return -1;
122         }
123     }
124
125     // Load input data
126     Mat left, right;
127     for (int i = 1; i < argc; ++i)
128     {
129         if (string(argv[i]) == "--left")
130         {
131             left = imread(argv[++i], cv::IMREAD_GRAYSCALE);
132             CV_Assert(!left.empty());
133         }
134         else if (string(argv[i]) == "--right")
135         {
136             right = imread(argv[++i], cv::IMREAD_GRAYSCALE);
137             CV_Assert(!right.empty());
138         }
139         else if (string(argv[i]) == "--help")
140         {
141             printHelp();
142             return -1;
143         }
144     }
145
146
147     // Init CUDA Driver API
148     safeCall(cuInit(0));
149
150     // Create context for GPU #0
151     CUdevice device;
152     safeCall(cuDeviceGet(&device, 0));
153     safeCall(cuCtxCreate(&contexts[0], 0, device));
154     contextOff();
155
156     // Create context for GPU #1
157     safeCall(cuDeviceGet(&device, 1));
158     safeCall(cuCtxCreate(&contexts[1], 0, device));
159     contextOff();
160
161     // Split source images for processing on GPU #0
162     contextOn(0);
163     d_left[0].upload(left.rowRange(0, left.rows / 2));
164     d_right[0].upload(right.rowRange(0, right.rows / 2));
165     bm[0] = cuda::createStereoBM();
166     contextOff();
167
168     // Split source images for processing on the GPU #1
169     contextOn(1);
170     d_left[1].upload(left.rowRange(left.rows / 2, left.rows));
171     d_right[1].upload(right.rowRange(right.rows / 2, right.rows));
172     bm[1] = cuda::createStereoBM();
173     contextOff();
174
175     // Execute calculation in two threads using two GPUs
176     int devices[] = {0, 1};
177     tbb::parallel_do(devices, devices + 2, Worker());
178
179     // Release the first GPU resources
180     contextOn(0);
181     imshow("GPU #0 result", Mat(d_result[0]));
182     d_left[0].release();
183     d_right[0].release();
184     d_result[0].release();
185     bm[0].release();
186     contextOff();
187
188     // Release the second GPU resources
189     contextOn(1);
190     imshow("GPU #1 result", Mat(d_result[1]));
191     d_left[1].release();
192     d_right[1].release();
193     d_result[1].release();
194     bm[1].release();
195     contextOff();
196
197     waitKey();
198     destroyContexts();
199     return 0;
200 }
201
202
203 void Worker::operator()(int device_id) const
204 {
205     contextOn(device_id);
206
207     bm[device_id]->compute(d_left[device_id], d_right[device_id], d_result[device_id]);
208
209     std::cout << "GPU #" << device_id << " (" << DeviceInfo().name()
210         << "): finished\n";
211
212     contextOff();
213 }
214
215
216 void destroyContexts()
217 {
218     safeCall(cuCtxDestroy(contexts[0]));
219     safeCall(cuCtxDestroy(contexts[1]));
220 }
221
222 #endif