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
5 // Disable some warnings which are caused with CUDA headers
7 #pragma warning(disable: 4201 4408 4100)
12 #include "opencv2/core/core.hpp"
13 #include "opencv2/highgui/highgui.hpp"
14 #include "opencv2/cudastereo.hpp"
17 # include "tbb/tbb_stddef.h"
18 # if TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202
20 # include "tbb/task.h"
28 #if !defined(HAVE_CUDA) || !defined(HAVE_TBB) || defined(__arm__)
32 #if !defined(HAVE_CUDA)
33 std::cout << "CUDA support is required (CMake key 'WITH_CUDA' must be true).\n";
36 #if !defined(HAVE_TBB)
37 std::cout << "TBB support is required (CMake key 'WITH_TBB' must be true).\n";
41 std::cout << "Unsupported for ARM CUDA library." << std::endl;
50 #include <cuda_runtime.h>
54 using namespace cv::cuda;
56 struct Worker { void operator()(int device_id) const; };
57 void destroyContexts();
59 #define safeCall(expr) safeCall_(expr, #expr, __FILE__, __LINE__)
60 inline void safeCall_(int code, const char* expr, const char* file, int line)
62 if (code != CUDA_SUCCESS)
64 std::cout << "CUDA driver API error: code " << code << ", expr " << expr
65 << ", file " << file << ", line " << line << endl;
71 // Each GPU is associated with its own context
72 CUcontext contexts[2];
74 void inline contextOn(int id)
76 safeCall(cuCtxPushCurrent(contexts[id]));
79 void inline contextOff()
81 CUcontext prev_context;
82 safeCall(cuCtxPopCurrent(&prev_context));
88 Ptr<cuda::StereoBM> bm[2];
91 static void printHelp()
93 std::cout << "Usage: driver_api_stereo_multi_gpu --left <left_image> --right <right_image>\n";
96 int main(int argc, char** argv)
104 int num_devices = getCudaEnabledDeviceCount();
107 std::cout << "Two or more GPUs are required\n";
111 for (int i = 0; i < num_devices; ++i)
113 cv::cuda::printShortCudaDeviceInfo(i);
115 DeviceInfo dev_info(i);
116 if (!dev_info.isCompatible())
118 std::cout << "GPU module isn't built for GPU #" << i << " ("
119 << dev_info.name() << ", CC " << dev_info.majorVersion()
120 << dev_info.minorVersion() << "\n";
127 for (int i = 1; i < argc; ++i)
129 if (string(argv[i]) == "--left")
131 left = imread(argv[++i], cv::IMREAD_GRAYSCALE);
132 CV_Assert(!left.empty());
134 else if (string(argv[i]) == "--right")
136 right = imread(argv[++i], cv::IMREAD_GRAYSCALE);
137 CV_Assert(!right.empty());
139 else if (string(argv[i]) == "--help")
147 // Init CUDA Driver API
150 // Create context for GPU #0
152 safeCall(cuDeviceGet(&device, 0));
153 safeCall(cuCtxCreate(&contexts[0], 0, device));
156 // Create context for GPU #1
157 safeCall(cuDeviceGet(&device, 1));
158 safeCall(cuCtxCreate(&contexts[1], 0, device));
161 // Split source images for processing on GPU #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();
168 // Split source images for processing on the GPU #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();
175 // Execute calculation in two threads using two GPUs
176 int devices[] = {0, 1};
177 tbb::parallel_do(devices, devices + 2, Worker());
179 // Release the first GPU resources
181 imshow("GPU #0 result", Mat(d_result[0]));
183 d_right[0].release();
184 d_result[0].release();
188 // Release the second GPU resources
190 imshow("GPU #1 result", Mat(d_result[1]));
192 d_right[1].release();
193 d_result[1].release();
203 void Worker::operator()(int device_id) const
205 contextOn(device_id);
207 bm[device_id]->compute(d_left[device_id], d_right[device_id], d_result[device_id]);
209 std::cout << "GPU #" << device_id << " (" << DeviceInfo().name()
216 void destroyContexts()
218 safeCall(cuCtxDestroy(contexts[0]));
219 safeCall(cuCtxDestroy(contexts[1]));