test_opencl.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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. #include "../test_precomp.hpp"
  5. #include <opencv2/core/ocl.hpp>
  6. namespace opencv_test { namespace {
  7. static void testOpenCLKernel(cv::ocl::Kernel& k)
  8. {
  9. ASSERT_FALSE(k.empty());
  10. cv::UMat src(cv::Size(4096, 2048), CV_8UC1, cv::Scalar::all(100));
  11. cv::UMat dst(src.size(), CV_8UC1);
  12. size_t globalSize[2] = {(size_t)src.cols, (size_t)src.rows};
  13. size_t localSize[2] = {8, 8};
  14. int64 kernel_time = k.args(
  15. cv::ocl::KernelArg::ReadOnlyNoSize(src), // size is not used (similar to 'dst' size)
  16. cv::ocl::KernelArg::WriteOnly(dst),
  17. (int)5
  18. ).runProfiling(2, globalSize, localSize);
  19. ASSERT_GE(kernel_time, (int64)0);
  20. std::cout << "Kernel time: " << (kernel_time * 1e-6) << " ms" << std::endl;
  21. cv::Mat res, reference(src.size(), CV_8UC1, cv::Scalar::all(105));
  22. dst.copyTo(res);
  23. EXPECT_EQ(0, cvtest::norm(reference, res, cv::NORM_INF));
  24. }
  25. TEST(OpenCL, support_binary_programs)
  26. {
  27. cv::ocl::Context ctx = cv::ocl::Context::getDefault();
  28. if (!ctx.ptr())
  29. {
  30. throw cvtest::SkipTestException("OpenCL is not available");
  31. }
  32. cv::ocl::Device device = cv::ocl::Device::getDefault();
  33. if (!device.compilerAvailable())
  34. {
  35. throw cvtest::SkipTestException("OpenCL compiler is not available");
  36. }
  37. std::vector<char> program_binary_code;
  38. cv::String module_name; // empty to disable OpenCL cache
  39. { // Generate program binary from OpenCL C source
  40. static const char* opencl_kernel_src =
  41. "__kernel void test_kernel(__global const uchar* src, int src_step, int src_offset,\n"
  42. " __global uchar* dst, int dst_step, int dst_offset, int dst_rows, int dst_cols,\n"
  43. " int c)\n"
  44. "{\n"
  45. " int x = get_global_id(0);\n"
  46. " int y = get_global_id(1);\n"
  47. " if (x < dst_cols && y < dst_rows)\n"
  48. " {\n"
  49. " int src_idx = y * src_step + x + src_offset;\n"
  50. " int dst_idx = y * dst_step + x + dst_offset;\n"
  51. " dst[dst_idx] = src[src_idx] + c;\n"
  52. " }\n"
  53. "}\n";
  54. cv::ocl::ProgramSource src(module_name, "simple", opencl_kernel_src, "");
  55. cv::String errmsg;
  56. cv::ocl::Program program(src, "", errmsg);
  57. ASSERT_TRUE(program.ptr() != NULL);
  58. cv::ocl::Kernel k("test_kernel", program);
  59. EXPECT_FALSE(k.empty());
  60. program.getBinary(program_binary_code);
  61. std::cout << "Program binary size: " << program_binary_code.size() << " bytes" << std::endl;
  62. }
  63. cv::ocl::Kernel k;
  64. { // Load program from binary (without sources)
  65. ASSERT_FALSE(program_binary_code.empty());
  66. cv::ocl::ProgramSource src = cv::ocl::ProgramSource::fromBinary(module_name, "simple_binary", (uchar*)&program_binary_code[0], program_binary_code.size(), "");
  67. cv::String errmsg;
  68. cv::ocl::Program program(src, "", errmsg);
  69. ASSERT_TRUE(program.ptr() != NULL);
  70. k.create("test_kernel", program);
  71. }
  72. testOpenCLKernel(k);
  73. }
  74. TEST(OpenCL, support_SPIR_programs)
  75. {
  76. cv::ocl::Context ctx = cv::ocl::Context::getDefault();
  77. if (!ctx.ptr())
  78. {
  79. throw cvtest::SkipTestException("OpenCL is not available");
  80. }
  81. cv::ocl::Device device = cv::ocl::Device::getDefault();
  82. if (!device.isExtensionSupported("cl_khr_spir"))
  83. {
  84. throw cvtest::SkipTestException("'cl_khr_spir' extension is not supported by OpenCL device");
  85. }
  86. std::vector<char> program_binary_code;
  87. cv::String fname = cv::format("test_kernel.spir%d", device.addressBits());
  88. std::string full_path = cvtest::findDataFile(std::string("opencl/") + fname);
  89. {
  90. std::fstream f(full_path.c_str(), std::ios::in|std::ios::binary);
  91. ASSERT_TRUE(f.is_open());
  92. size_t pos = (size_t)f.tellg();
  93. f.seekg(0, std::fstream::end);
  94. size_t fileSize = (size_t)f.tellg();
  95. std::cout << "Program SPIR size: " << fileSize << " bytes" << std::endl;
  96. f.seekg(pos, std::fstream::beg);
  97. program_binary_code.resize(fileSize);
  98. f.read(&program_binary_code[0], fileSize);
  99. ASSERT_FALSE(f.fail());
  100. }
  101. cv::String module_name; // empty to disable OpenCL cache
  102. cv::ocl::Kernel k;
  103. { // Load program from SPIR format
  104. ASSERT_FALSE(program_binary_code.empty());
  105. cv::ocl::ProgramSource src = cv::ocl::ProgramSource::fromSPIR(module_name, "simple_spir", (uchar*)&program_binary_code[0], program_binary_code.size(), "");
  106. cv::String errmsg;
  107. cv::ocl::Program program(src, "", errmsg);
  108. if (program.ptr() == NULL && device.isAMD())
  109. {
  110. // https://community.amd.com/t5/opencl/spir-support-in-new-drivers-lost/td-p/170165
  111. throw cvtest::SkipTestException("Bypass AMD OpenCL runtime bug: 'cl_khr_spir' extension is declared, but it doesn't really work");
  112. }
  113. ASSERT_TRUE(program.ptr() != NULL);
  114. k.create("test_kernel", program);
  115. }
  116. testOpenCLKernel(k);
  117. }
  118. TEST(OpenCL, image2Dcount_regression_19334)
  119. {
  120. cv::ocl::Context ctx = cv::ocl::Context::getDefault();
  121. if (!ctx.ptr())
  122. {
  123. throw cvtest::SkipTestException("OpenCL is not available");
  124. }
  125. cv::ocl::Device device = cv::ocl::Device::getDefault();
  126. if (!device.compilerAvailable())
  127. {
  128. throw cvtest::SkipTestException("OpenCL compiler is not available");
  129. }
  130. std::string module_name; // empty to disable OpenCL cache
  131. static const char* opencl_kernel_src =
  132. "__kernel void test_kernel(int a,\n"
  133. " __global const uchar* src0, int src0_step, int src0_offset, int src0_rows, int src0_cols,\n"
  134. " __global const uchar* src1, int src1_step, int src1_offset, int src1_rows, int src1_cols,\n"
  135. " __global const uchar* src2, int src2_step, int src2_offset, int src2_rows, int src2_cols,\n"
  136. " __read_only image2d_t image)\n"
  137. "{\n"
  138. "}";
  139. cv::ocl::ProgramSource src(module_name, "test_opencl_image_arg", opencl_kernel_src, "");
  140. cv::String errmsg;
  141. cv::ocl::Program program(src, "", errmsg);
  142. ASSERT_TRUE(program.ptr() != NULL);
  143. cv::ocl::Kernel k("test_kernel", program);
  144. ASSERT_FALSE(k.empty());
  145. std::vector<UMat> images(4);
  146. for (size_t i = 0; i < images.size(); ++i)
  147. images[i] = UMat(10, 10, CV_8UC1);
  148. cv::ocl::Image2D image;
  149. try
  150. {
  151. cv::ocl::Image2D image_(images.back());
  152. image = image_;
  153. }
  154. catch (const cv::Exception&)
  155. {
  156. throw cvtest::SkipTestException("OpenCL images are not supported");
  157. }
  158. int nargs = 0;
  159. int a = 0;
  160. nargs = k.set(nargs, a);
  161. ASSERT_EQ(1, nargs);
  162. nargs = k.set(nargs, images[0]);
  163. ASSERT_EQ(6, nargs);
  164. nargs = k.set(nargs, images[1]);
  165. ASSERT_EQ(11, nargs);
  166. nargs = k.set(nargs, images[2]);
  167. ASSERT_EQ(16, nargs);
  168. // do not throw (issue of #19334)
  169. ASSERT_NO_THROW(nargs = k.set(nargs, image));
  170. ASSERT_EQ(17, nargs);
  171. // allow to replace image argument if kernel is not running
  172. UMat image2(10, 10, CV_8UC1);
  173. ASSERT_NO_THROW(nargs = k.set(16, cv::ocl::Image2D(image2)));
  174. ASSERT_EQ(17, nargs);
  175. }
  176. TEST(OpenCL, move_construct_assign)
  177. {
  178. cv::ocl::Context ctx1 = cv::ocl::Context::getDefault();
  179. if (!ctx1.ptr())
  180. {
  181. throw cvtest::SkipTestException("OpenCL is not available");
  182. }
  183. void* const ctx_ptr = ctx1.ptr();
  184. cv::ocl::Context ctx2(std::move(ctx1));
  185. ASSERT_EQ(ctx1.ptr(), nullptr);
  186. ASSERT_EQ(ctx2.ptr(), ctx_ptr);
  187. cv::ocl::Context ctx3 = std::move(ctx2);
  188. ASSERT_EQ(ctx2.ptr(), nullptr);
  189. ASSERT_EQ(ctx3.ptr(), ctx_ptr);
  190. cv::ocl::Platform pl1 = cv::ocl::Platform::getDefault();
  191. void* const pl_ptr = pl1.ptr();
  192. cv::ocl::Platform pl2(std::move(pl1));
  193. ASSERT_EQ(pl1.ptr(), nullptr);
  194. ASSERT_EQ(pl2.ptr(), pl_ptr);
  195. cv::ocl::Platform pl3 = std::move(pl2);
  196. ASSERT_EQ(pl2.ptr(), nullptr);
  197. ASSERT_EQ(pl3.ptr(), pl_ptr);
  198. std::vector<cv::ocl::PlatformInfo> platformInfos;
  199. cv::ocl::getPlatfomsInfo(platformInfos);
  200. const cv::String pi_name = platformInfos[0].name();
  201. cv::ocl::PlatformInfo pinfo2(std::move(platformInfos[0]));
  202. ASSERT_EQ(platformInfos[0].name(), cv::String());
  203. ASSERT_EQ(pinfo2.name(), pi_name);
  204. cv::ocl::PlatformInfo pinfo3 = std::move(pinfo2);
  205. ASSERT_EQ(pinfo2.name(), cv::String());
  206. ASSERT_EQ(pinfo3.name(), pi_name);
  207. cv::ocl::Queue q1 = cv::ocl::Queue::getDefault();
  208. void* const q_ptr = q1.ptr();
  209. cv::ocl::Queue q2(std::move(q1));
  210. ASSERT_EQ(q1.ptr(), nullptr);
  211. ASSERT_EQ(q2.ptr(), q_ptr);
  212. cv::ocl::Queue q3 = std::move(q2);
  213. ASSERT_EQ(q2.ptr(), nullptr);
  214. ASSERT_EQ(q3.ptr(), q_ptr);
  215. cv::ocl::Device d1 = cv::ocl::Device::getDefault();
  216. if (!d1.compilerAvailable())
  217. {
  218. throw cvtest::SkipTestException("OpenCL compiler is not available");
  219. }
  220. void* const d_ptr = d1.ptr();
  221. cv::ocl::Device d2(std::move(d1));
  222. ASSERT_EQ(d1.ptr(), nullptr);
  223. ASSERT_EQ(d2.ptr(), d_ptr);
  224. cv::ocl::Device d3 = std::move(d2);
  225. ASSERT_EQ(d2.ptr(), nullptr);
  226. ASSERT_EQ(d3.ptr(), d_ptr);
  227. if (d3.imageSupport()) {
  228. cv::UMat umat1 = cv::UMat::ones(640, 480, CV_32FC1);
  229. cv::ocl::Image2D img1(umat1);
  230. void *const img_ptr = img1.ptr();
  231. cv::ocl::Image2D img2(std::move(img1));
  232. ASSERT_EQ(img1.ptr(), nullptr);
  233. ASSERT_EQ(img2.ptr(), img_ptr);
  234. cv::ocl::Image2D img3 = std::move(img2);
  235. ASSERT_EQ(img2.ptr(), nullptr);
  236. ASSERT_EQ(img3.ptr(), img_ptr);
  237. }
  238. static const char* opencl_kernel_src =
  239. "__kernel void test_kernel(__global const uchar* src, int src_step, int src_offset,\n"
  240. " __global uchar* dst, int dst_step, int dst_offset, int dst_rows, int dst_cols,\n"
  241. " int c)\n"
  242. "{\n"
  243. " int x = get_global_id(0);\n"
  244. " int y = get_global_id(1);\n"
  245. " if (x < dst_cols && y < dst_rows)\n"
  246. " {\n"
  247. " int src_idx = y * src_step + x + src_offset;\n"
  248. " int dst_idx = y * dst_step + x + dst_offset;\n"
  249. " dst[dst_idx] = src[src_idx] + c;\n"
  250. " }\n"
  251. "}\n";
  252. cv::String module_name; // empty to disable OpenCL cache
  253. cv::ocl::ProgramSource ps1(module_name, "move_construct_assign", opencl_kernel_src, "");
  254. cv::ocl::ProgramSource::Impl* const ps_ptr = ps1.getImpl();
  255. cv::ocl::ProgramSource ps2(std::move(ps1));
  256. ASSERT_EQ(ps1.getImpl(), nullptr);
  257. ASSERT_EQ(ps2.getImpl(), ps_ptr);
  258. cv::ocl::ProgramSource ps3 = std::move(ps2);
  259. ASSERT_EQ(ps2.getImpl(), nullptr);
  260. ASSERT_EQ(ps3.getImpl(), ps_ptr);
  261. cv::String errmsg;
  262. cv::ocl::Program prog1(ps3, "", errmsg);
  263. void* const prog_ptr = prog1.ptr();
  264. ASSERT_NE(prog_ptr, nullptr);
  265. cv::ocl::Program prog2(std::move(prog1));
  266. ASSERT_EQ(prog1.ptr(), nullptr);
  267. ASSERT_EQ(prog2.ptr(), prog_ptr);
  268. cv::ocl::Program prog3 = std::move(prog2);
  269. ASSERT_EQ(prog2.ptr(), nullptr);
  270. ASSERT_EQ(prog3.ptr(), prog_ptr);
  271. cv::ocl::Kernel k1("test_kernel", prog3);
  272. void* const k_ptr = k1.ptr();
  273. ASSERT_NE(k_ptr, nullptr);
  274. cv::ocl::Kernel k2(std::move(k1));
  275. ASSERT_EQ(k1.ptr(), nullptr);
  276. ASSERT_EQ(k2.ptr(), k_ptr);
  277. cv::ocl::Kernel k3 = std::move(k2);
  278. ASSERT_EQ(k2.ptr(), nullptr);
  279. ASSERT_EQ(k3.ptr(), k_ptr);
  280. testOpenCLKernel(k3);
  281. }
  282. }} // namespace