1
0

ClGenerators.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. #include "ClGenerators.h"
  2. #include "doubledouble.h"
  3. #ifdef WITH_OPENCL
  4. #include <iostream>
  5. #include <iterator>
  6. using namespace cl;
  7. using mnd::ClGenerator;
  8. using mnd::ClGeneratorFloat;
  9. using mnd::ClGeneratorDouble;
  10. using mnd::ClGeneratorDoubleDouble;
  11. using mnd::ClGeneratorQuadDouble;
  12. using mnd::ClGenerator128;
  13. Platform getPlatform() {
  14. /* Returns the first platform found. */
  15. std::vector<Platform> all_platforms;
  16. Platform::get(&all_platforms);
  17. if (all_platforms.size() == 0) {
  18. std::cout << "No platforms found. Check OpenCL installation!\n";
  19. exit(1);
  20. }
  21. for (auto& p : all_platforms) {
  22. std::string name = p.getInfo<CL_PLATFORM_NAME>();
  23. std::string profile = p.getInfo<CL_PLATFORM_PROFILE>();
  24. printf("Platform: %s, %s\n", name.c_str(), profile.c_str());
  25. }
  26. return all_platforms[0];
  27. }
  28. Device getDevice(Platform& platform, int i, bool display = false) {
  29. /* Returns the deviced specified by the index i on platform.
  30. * If display is true, then all of the platforms are listed.
  31. */
  32. std::vector<Device> all_devices;
  33. platform.getDevices(CL_DEVICE_TYPE_ALL, &all_devices);
  34. if (all_devices.size() == 0) {
  35. std::cout << "No devices found. Check OpenCL installation!\n";
  36. exit(1);
  37. }
  38. if (display) {
  39. for (::size_t j = 0; j < all_devices.size(); j++) {
  40. printf("Device %d: %s\n", int(j), all_devices[j].getInfo<CL_DEVICE_NAME>().c_str());
  41. printf("preferred float width: %d\n", all_devices[j].getInfo<CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT>());
  42. printf("vendor: %s\n", all_devices[j].getInfo<CL_DEVICE_VENDOR>().c_str());
  43. }
  44. }
  45. return all_devices[i];
  46. }
  47. ClGenerator::ClGenerator(cl::Device device) :
  48. device{ device }
  49. {
  50. /*Platform p = getPlatform();
  51. device = getDevice(p, 0, true);
  52. context = Context{ device };
  53. Program::Sources sources;
  54. std::string kcode = this->getKernelCode();
  55. sources.push_back({ kcode.c_str(), kcode.length() });
  56. program = Program{ context, sources };
  57. if (program.build({ device }) != CL_SUCCESS) {
  58. std::cout << "Error building: " << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device) << std::endl;
  59. exit(1);
  60. }
  61. queue = CommandQueue(context, device);*/
  62. }
  63. ClGenerator::~ClGenerator(void)
  64. {
  65. queue.flush();
  66. queue.finish();
  67. }
  68. void ClGenerator::generate(const mnd::MandelInfo& info, float* data)
  69. {
  70. ::size_t bufferSize = info.bWidth * info.bHeight * sizeof(float);
  71. Buffer buffer_A(context, CL_MEM_WRITE_ONLY, bufferSize);
  72. float pixelScaleX = float(info.view.width / info.bWidth);
  73. float pixelScaleY = float(info.view.height / info.bHeight);
  74. Kernel iterate = Kernel(program, "iterate");
  75. iterate.setArg(0, buffer_A);
  76. iterate.setArg(1, int(info.bWidth));
  77. iterate.setArg(2, float(info.view.x));
  78. iterate.setArg(3, float(info.view.y));
  79. iterate.setArg(4, float(pixelScaleX));
  80. iterate.setArg(5, float(pixelScaleY));
  81. iterate.setArg(6, int(info.maxIter));
  82. iterate.setArg(7, int(info.smooth ? 1 : 0));
  83. // TODO check for overflow
  84. if (false && device.getInfo<CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT>() == 4) {
  85. queue.enqueueNDRangeKernel(iterate, 0, NDRange(info.bWidth * info.bHeight / 4));
  86. } else {
  87. queue.enqueueNDRangeKernel(iterate, 0, NDRange(info.bWidth * info.bHeight));
  88. }
  89. queue.enqueueReadBuffer(buffer_A, CL_TRUE, 0, bufferSize, data);
  90. }
  91. ClGeneratorFloat::ClGeneratorFloat(cl::Device device) :
  92. ClGenerator{ device }
  93. {
  94. context = Context{ device };
  95. Program::Sources sources;
  96. std::string kcode = this->getKernelCode(false);
  97. sources.push_back({ kcode.c_str(), kcode.length() });
  98. program = Program{ context, sources };
  99. if (program.build({ device }) != CL_SUCCESS) {
  100. throw std::string(program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device));
  101. }
  102. queue = CommandQueue(context, device);
  103. }
  104. std::string ClGeneratorFloat::getKernelCode(bool smooth) const
  105. {
  106. return
  107. // "#pragma OPENCL EXTENSION cl_khr_fp64 : enable"
  108. "__kernel void iterate(__global float* A, const int width, float xl, float yt, float pixelScaleX, float pixelScaleY, int max, int smooth) {"
  109. " int index = get_global_id(0);\n"
  110. " int x = index % width;"
  111. " int y = index / width;"
  112. " float a = x * pixelScaleX + xl;"
  113. " float b = y * pixelScaleY + yt;"
  114. " float ca = a;"
  115. " float cb = b;"
  116. ""
  117. " int n = 0;"
  118. " while (n < max - 1) {"
  119. " float aa = a * a;"
  120. " float bb = b * b;"
  121. " float ab = a * b;"
  122. " if (aa + bb > 16) break;"
  123. " a = aa - bb + ca;"
  124. " b = 2 * ab + cb;"
  125. " n++;"
  126. " }\n"
  127. " if (n >= max - 1)\n"
  128. " A[index] = max;\n"
  129. " else {"
  130. " if (smooth != 0)\n"
  131. " A[index] = ((float)n) + 1 - log(log(a * a + b * b) / 2) / log(2.0f);\n"
  132. " else\n"
  133. " A[index] = ((float)n);\n"
  134. " }"
  135. "}";
  136. }
  137. ClGeneratorDouble::ClGeneratorDouble(cl::Device device) :
  138. ClGenerator{ device }
  139. {
  140. context = Context{ device };
  141. Program::Sources sources;
  142. std::string kcode = this->getKernelCode(false);
  143. sources.push_back({ kcode.c_str(), kcode.length() });
  144. program = Program{ context, sources };
  145. if (program.build({ device }) != CL_SUCCESS) {
  146. throw std::string(program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device));
  147. }
  148. queue = CommandQueue(context, device);
  149. }
  150. void ClGeneratorDouble::generate(const mnd::MandelInfo& info, float* data)
  151. {
  152. ::size_t bufferSize = info.bWidth * info.bHeight * sizeof(float);
  153. Buffer buffer_A(context, CL_MEM_WRITE_ONLY, bufferSize);
  154. double pixelScaleX = double(info.view.width / info.bWidth);
  155. double pixelScaleY = double(info.view.height / info.bHeight);
  156. Kernel iterate = Kernel(program, "iterate");
  157. iterate.setArg(0, buffer_A);
  158. iterate.setArg(1, int(info.bWidth));
  159. iterate.setArg(2, double(info.view.x));
  160. iterate.setArg(3, double(info.view.y));
  161. iterate.setArg(4, double(pixelScaleX));
  162. iterate.setArg(5, double(pixelScaleY));
  163. iterate.setArg(6, int(info.maxIter));
  164. iterate.setArg(7, int(info.smooth ? 1 : 0));
  165. cl_int result = queue.enqueueNDRangeKernel(iterate, 0, NDRange(info.bWidth * info.bHeight));
  166. queue.enqueueReadBuffer(buffer_A, CL_TRUE, 0, bufferSize, data);
  167. }
  168. std::string ClGeneratorDouble::getKernelCode(bool smooth) const
  169. {
  170. return
  171. "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n"
  172. "__kernel void iterate(__global float* A, const int width, double xl, double yt, double pixelScaleX, double pixelScaleY, int max, int smooth) {\n"
  173. " int index = get_global_id(0);\n"
  174. " int x = index % width;"
  175. " int y = index / width;"
  176. " double a = x * pixelScaleX + xl;"
  177. " double b = y * pixelScaleY + yt;"
  178. " double ca = a;"
  179. " double cb = b;"
  180. ""
  181. " int n = 0;"
  182. " while (n < max - 1) {"
  183. " double aa = a * a;"
  184. " double bb = b * b;"
  185. " double ab = a * b;"
  186. " if (aa + bb > 16) break;"
  187. " a = aa - bb + ca;"
  188. " b = 2 * ab + cb;"
  189. " n++;"
  190. " }\n"
  191. // N + 1 - log (log |Z(N)|) / log 2
  192. " if (n >= max - 1)\n"
  193. " A[index] = max;\n"
  194. " else {"
  195. " if (smooth != 0)\n"
  196. " A[index] = ((float)n) + 1 - log(log((float)(a * a + b * b)) / 2) / log(2.0f);\n"
  197. " else\n"
  198. " A[index] = ((float)n);\n"
  199. " }"
  200. "}";
  201. }
  202. ClGeneratorDoubleDouble::ClGeneratorDoubleDouble(cl::Device device) :
  203. ClGenerator{ device }
  204. {
  205. context = Context{ device };
  206. Program::Sources sources;
  207. std::string kcode = this->getKernelCode(false);
  208. sources.push_back({ kcode.c_str(), kcode.length() });
  209. program = Program{ context, sources };
  210. if (program.build({ device }) != CL_SUCCESS) {
  211. throw std::string(program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device));
  212. }
  213. queue = CommandQueue(context, device);
  214. }
  215. void ClGeneratorDoubleDouble::generate(const mnd::MandelInfo& info, float* data)
  216. {
  217. ::size_t bufferSize = info.bWidth * info.bHeight * sizeof(float);
  218. Buffer buffer_A(context, CL_MEM_WRITE_ONLY, bufferSize);
  219. mnd::DoubleDouble x = mnd::convert<mnd::DoubleDouble>(info.view.x);
  220. mnd::DoubleDouble y = mnd::convert<mnd::DoubleDouble>(info.view.y);
  221. mnd::DoubleDouble psx = mnd::convert<mnd::DoubleDouble>(info.view.width / info.bWidth);
  222. mnd::DoubleDouble psy = mnd::convert<mnd::DoubleDouble>(info.view.height / info.bHeight);
  223. Kernel iterate = Kernel(program, "iterate");
  224. iterate.setArg(0, buffer_A);
  225. iterate.setArg(1, int(info.bWidth));
  226. iterate.setArg(2, x.x[0]);
  227. iterate.setArg(3, x.x[1]);
  228. iterate.setArg(4, y.x[0]);
  229. iterate.setArg(5, y.x[1]);
  230. iterate.setArg(6, psx.x[0]);
  231. iterate.setArg(7, psx.x[1]);
  232. iterate.setArg(8, psy.x[0]);
  233. iterate.setArg(9, psy.x[1]);
  234. iterate.setArg(10, int(info.maxIter));
  235. iterate.setArg(11, int(info.smooth ? 1 : 0));
  236. cl_int result = queue.enqueueNDRangeKernel(iterate, 0, NDRange(info.bWidth * info.bHeight));
  237. queue.enqueueReadBuffer(buffer_A, CL_TRUE, 0, bufferSize, data);
  238. }
  239. std::string ClGeneratorDoubleDouble::getKernelCode(bool smooth) const
  240. {
  241. return (char*) doubledouble_cl;
  242. }
  243. ClGeneratorQuadDouble::ClGeneratorQuadDouble(cl::Device device) :
  244. ClGenerator{ device }
  245. {
  246. context = Context{ device };
  247. Program::Sources sources;
  248. std::string kcode = this->getKernelCode(false);
  249. sources.push_back({ kcode.c_str(), kcode.length() });
  250. program = Program{ context, sources };
  251. if (program.build({ device }) != CL_SUCCESS) {
  252. throw std::string(program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device));
  253. }
  254. queue = CommandQueue(context, device);
  255. }
  256. void ClGeneratorQuadDouble::generate(const mnd::MandelInfo& info, float* data)
  257. {
  258. ::size_t bufferSize = info.bWidth * info.bHeight * sizeof(float);
  259. Buffer buffer_A(context, CL_MEM_WRITE_ONLY, bufferSize);
  260. mnd::DoubleDouble x = mnd::convert<mnd::DoubleDouble>(info.view.x);
  261. mnd::DoubleDouble y = mnd::convert<mnd::DoubleDouble>(info.view.y);
  262. mnd::DoubleDouble psx = mnd::convert<mnd::DoubleDouble>(info.view.width / info.bWidth);
  263. mnd::DoubleDouble psy = mnd::convert<mnd::DoubleDouble>(info.view.height / info.bHeight);
  264. Kernel iterate = Kernel(program, "iterate");
  265. iterate.setArg(0, buffer_A);
  266. iterate.setArg(1, int(info.bWidth));
  267. iterate.setArg(2, x.x[0]);
  268. iterate.setArg(3, x.x[1]);
  269. iterate.setArg(4, y.x[0]);
  270. iterate.setArg(5, y.x[1]);
  271. iterate.setArg(6, psx.x[0]);
  272. iterate.setArg(7, psx.x[1]);
  273. iterate.setArg(8, psy.x[0]);
  274. iterate.setArg(9, psy.x[1]);
  275. iterate.setArg(10, int(info.maxIter));
  276. iterate.setArg(11, int(info.smooth ? 1 : 0));
  277. cl_int result = queue.enqueueNDRangeKernel(iterate, 0, NDRange(info.bWidth * info.bHeight));
  278. queue.enqueueReadBuffer(buffer_A, CL_TRUE, 0, bufferSize, data);
  279. }
  280. std::string ClGeneratorQuadDouble::getKernelCode(bool smooth) const
  281. {
  282. return (char*) doubledouble_cl;
  283. }
  284. ClGenerator128::ClGenerator128(cl::Device device) :
  285. ClGenerator{ device }
  286. {
  287. context = Context{ device };
  288. Program::Sources sources;
  289. std::string kcode = this->getKernelCode(false);
  290. sources.push_back({ kcode.c_str(), kcode.length() });
  291. program = Program{ context, sources };
  292. if (program.build({ device }) != CL_SUCCESS) {
  293. throw std::string(program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device));
  294. }
  295. queue = CommandQueue(context, device);
  296. }
  297. void ClGenerator128::generate(const mnd::MandelInfo& info, float* data)
  298. {
  299. ::size_t bufferSize = info.bWidth * info.bHeight * sizeof(float);
  300. Buffer buffer_A(context, CL_MEM_WRITE_ONLY, bufferSize);
  301. float pixelScaleX = float(info.view.width / info.bWidth);
  302. float pixelScaleY = float(info.view.height / info.bHeight);
  303. Kernel iterate = Kernel(program, "iterate");
  304. iterate.setArg(0, buffer_A);
  305. iterate.setArg(1, int(info.bWidth));
  306. iterate.setArg(2, double(info.view.x));
  307. iterate.setArg(3, double(info.view.y));
  308. iterate.setArg(4, double(pixelScaleX));
  309. iterate.setArg(5, double(pixelScaleY));
  310. iterate.setArg(6, int(info.maxIter));
  311. queue.enqueueNDRangeKernel(iterate, 0, NDRange(info.bWidth * info.bHeight));
  312. queue.enqueueReadBuffer(buffer_A, CL_TRUE, 0, bufferSize, data);
  313. }
  314. #include <string>
  315. #include <fstream>
  316. #include <streambuf>
  317. std::string ClGenerator128::getKernelCode(bool smooth) const
  318. {
  319. //fprintf(stderr, "starting file read\n");
  320. std::ifstream t("mandel128.cl");
  321. std::string str((std::istreambuf_iterator<char>(t)),
  322. std::istreambuf_iterator<char>());
  323. //fprintf(stderr, "%s\n", str);
  324. return str;
  325. }
  326. #endif // WITH_OPENCL