ClGenerators.cpp 12 KB

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