program.hpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. // See http://boostorg.github.com/compute for more information.
  9. //---------------------------------------------------------------------------//
  10. #ifndef BOOST_COMPUTE_PROGRAM_HPP
  11. #define BOOST_COMPUTE_PROGRAM_HPP
  12. #include <string>
  13. #include <vector>
  14. #include <fstream>
  15. #include <streambuf>
  16. #ifdef BOOST_COMPUTE_DEBUG_KERNEL_COMPILATION
  17. #include <iostream>
  18. #endif
  19. #include <boost/compute/config.hpp>
  20. #include <boost/compute/context.hpp>
  21. #include <boost/compute/exception.hpp>
  22. #include <boost/compute/exception/program_build_failure.hpp>
  23. #include <boost/compute/detail/assert_cl_success.hpp>
  24. #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
  25. #include <sstream>
  26. #include <boost/optional.hpp>
  27. #include <boost/compute/platform.hpp>
  28. #include <boost/compute/detail/getenv.hpp>
  29. #include <boost/compute/detail/path.hpp>
  30. #include <boost/compute/detail/sha1.hpp>
  31. #endif
  32. namespace boost {
  33. namespace compute {
  34. class kernel;
  35. /// \class program
  36. /// \brief A compute program.
  37. ///
  38. /// The program class represents an OpenCL program.
  39. ///
  40. /// Program objects are created with one of the static \c create_with_*
  41. /// functions. For example, to create a program from a source string:
  42. ///
  43. /// \snippet test/test_program.cpp create_with_source
  44. ///
  45. /// And to create a program from a source file:
  46. /// \code
  47. /// boost::compute::program bar_program =
  48. /// boost::compute::program::create_with_source_file("/path/to/bar.cl", context);
  49. /// \endcode
  50. ///
  51. /// Once a program object has been successfully created, it can be compiled
  52. /// using the \c build() method:
  53. /// \code
  54. /// // build the program
  55. /// foo_program.build();
  56. /// \endcode
  57. ///
  58. /// Once the program is built, \ref kernel objects can be created using the
  59. /// \c create_kernel() method by passing their name:
  60. /// \code
  61. /// // create a kernel from the compiled program
  62. /// boost::compute::kernel foo_kernel = foo_program.create_kernel("foo");
  63. /// \endcode
  64. ///
  65. /// \see kernel
  66. class program
  67. {
  68. public:
  69. /// Creates a null program object.
  70. program()
  71. : m_program(0)
  72. {
  73. }
  74. /// Creates a program object for \p program. If \p retain is \c true,
  75. /// the reference count for \p program will be incremented.
  76. explicit program(cl_program program, bool retain = true)
  77. : m_program(program)
  78. {
  79. if(m_program && retain){
  80. clRetainProgram(m_program);
  81. }
  82. }
  83. /// Creates a new program object as a copy of \p other.
  84. program(const program &other)
  85. : m_program(other.m_program)
  86. {
  87. if(m_program){
  88. clRetainProgram(m_program);
  89. }
  90. }
  91. /// Copies the program object from \p other to \c *this.
  92. program& operator=(const program &other)
  93. {
  94. if(this != &other){
  95. if(m_program){
  96. clReleaseProgram(m_program);
  97. }
  98. m_program = other.m_program;
  99. if(m_program){
  100. clRetainProgram(m_program);
  101. }
  102. }
  103. return *this;
  104. }
  105. #ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES
  106. /// Move-constructs a new program object from \p other.
  107. program(program&& other) BOOST_NOEXCEPT
  108. : m_program(other.m_program)
  109. {
  110. other.m_program = 0;
  111. }
  112. /// Move-assigns the program from \p other to \c *this.
  113. program& operator=(program&& other) BOOST_NOEXCEPT
  114. {
  115. if(m_program){
  116. clReleaseProgram(m_program);
  117. }
  118. m_program = other.m_program;
  119. other.m_program = 0;
  120. return *this;
  121. }
  122. #endif // BOOST_COMPUTE_NO_RVALUE_REFERENCES
  123. /// Destroys the program object.
  124. ~program()
  125. {
  126. if(m_program){
  127. BOOST_COMPUTE_ASSERT_CL_SUCCESS(
  128. clReleaseProgram(m_program)
  129. );
  130. }
  131. }
  132. /// Returns the underlying OpenCL program.
  133. cl_program& get() const
  134. {
  135. return const_cast<cl_program &>(m_program);
  136. }
  137. /// Returns the source code for the program.
  138. std::string source() const
  139. {
  140. return get_info<std::string>(CL_PROGRAM_SOURCE);
  141. }
  142. /// Returns the binary for the program.
  143. std::vector<unsigned char> binary() const
  144. {
  145. size_t binary_size = get_info<size_t>(CL_PROGRAM_BINARY_SIZES);
  146. std::vector<unsigned char> binary(binary_size);
  147. unsigned char *binary_ptr = &binary[0];
  148. cl_int error = clGetProgramInfo(m_program,
  149. CL_PROGRAM_BINARIES,
  150. sizeof(unsigned char **),
  151. &binary_ptr,
  152. 0);
  153. if(error != CL_SUCCESS){
  154. BOOST_THROW_EXCEPTION(opencl_error(error));
  155. }
  156. return binary;
  157. }
  158. #if defined(BOOST_COMPUTE_CL_VERSION_2_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
  159. /// Returns the SPIR-V binary for the program.
  160. std::vector<unsigned char> il_binary() const
  161. {
  162. return get_info<std::vector<unsigned char> >(CL_PROGRAM_IL);
  163. }
  164. #endif // BOOST_COMPUTE_CL_VERSION_2_1
  165. std::vector<device> get_devices() const
  166. {
  167. std::vector<cl_device_id> device_ids =
  168. get_info<std::vector<cl_device_id> >(CL_PROGRAM_DEVICES);
  169. std::vector<device> devices;
  170. for(size_t i = 0; i < device_ids.size(); i++){
  171. devices.push_back(device(device_ids[i]));
  172. }
  173. return devices;
  174. }
  175. /// Returns the context for the program.
  176. context get_context() const
  177. {
  178. return context(get_info<cl_context>(CL_PROGRAM_CONTEXT));
  179. }
  180. /// Returns information about the program.
  181. ///
  182. /// \see_opencl_ref{clGetProgramInfo}
  183. template<class T>
  184. T get_info(cl_program_info info) const
  185. {
  186. return detail::get_object_info<T>(clGetProgramInfo, m_program, info);
  187. }
  188. /// \overload
  189. template<int Enum>
  190. typename detail::get_object_info_type<program, Enum>::type
  191. get_info() const;
  192. /// Returns build information about the program.
  193. ///
  194. /// For example, this function can be used to retreive the options used
  195. /// to build the program:
  196. /// \code
  197. /// std::string build_options =
  198. /// program.get_build_info<std::string>(CL_PROGRAM_BUILD_OPTIONS);
  199. /// \endcode
  200. ///
  201. /// \see_opencl_ref{clGetProgramInfo}
  202. template<class T>
  203. T get_build_info(cl_program_build_info info, const device &device) const
  204. {
  205. return detail::get_object_info<T>(clGetProgramBuildInfo, m_program, info, device.id());
  206. }
  207. /// Builds the program with \p options.
  208. ///
  209. /// If the program fails to compile, this function will throw an
  210. /// opencl_error exception.
  211. /// \code
  212. /// try {
  213. /// // attempt to compile to program
  214. /// program.build();
  215. /// }
  216. /// catch(boost::compute::opencl_error &e){
  217. /// // program failed to compile, print out the build log
  218. /// std::cout << program.build_log() << std::endl;
  219. /// }
  220. /// \endcode
  221. ///
  222. /// \see_opencl_ref{clBuildProgram}
  223. void build(const std::string &options = std::string())
  224. {
  225. const char *options_string = 0;
  226. if(!options.empty()){
  227. options_string = options.c_str();
  228. }
  229. cl_int ret = clBuildProgram(m_program, 0, 0, options_string, 0, 0);
  230. #ifdef BOOST_COMPUTE_DEBUG_KERNEL_COMPILATION
  231. if(ret != CL_SUCCESS){
  232. // print the error, source code and build log
  233. std::cerr << "Boost.Compute: "
  234. << "kernel compilation failed (" << ret << ")\n"
  235. << "--- source ---\n"
  236. << source()
  237. << "\n--- build log ---\n"
  238. << build_log()
  239. << std::endl;
  240. }
  241. #endif
  242. if(ret != CL_SUCCESS){
  243. BOOST_THROW_EXCEPTION(program_build_failure(ret, build_log()));
  244. }
  245. }
  246. #if defined(BOOST_COMPUTE_CL_VERSION_1_2) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
  247. /// Compiles the program with \p options.
  248. ///
  249. /// \opencl_version_warning{1,2}
  250. ///
  251. /// \see_opencl_ref{clCompileProgram}
  252. void compile(const std::string &options = std::string(),
  253. const std::vector<std::pair<std::string, program> > &headers =
  254. std::vector<std::pair<std::string, program> >())
  255. {
  256. const char *options_string = 0;
  257. if(!options.empty()){
  258. options_string = options.c_str();
  259. }
  260. cl_int ret;
  261. if (headers.empty())
  262. {
  263. ret = clCompileProgram(
  264. m_program, 0, 0, options_string, 0, 0, 0, 0, 0
  265. );
  266. }
  267. else
  268. {
  269. std::vector<const char*> header_names(headers.size());
  270. std::vector<cl_program> header_programs(headers.size());
  271. for (size_t i = 0; i < headers.size(); ++i)
  272. {
  273. header_names[i] = headers[i].first.c_str();
  274. header_programs[i] = headers[i].second.m_program;
  275. }
  276. ret = clCompileProgram(
  277. m_program,
  278. 0,
  279. 0,
  280. options_string,
  281. static_cast<cl_uint>(headers.size()),
  282. header_programs.data(),
  283. header_names.data(),
  284. 0,
  285. 0
  286. );
  287. }
  288. if(ret != CL_SUCCESS){
  289. BOOST_THROW_EXCEPTION(opencl_error(ret));
  290. }
  291. }
  292. /// Links the programs in \p programs with \p options in \p context.
  293. ///
  294. /// \opencl_version_warning{1,2}
  295. ///
  296. /// \see_opencl_ref{clLinkProgram}
  297. static program link(const std::vector<program> &programs,
  298. const context &context,
  299. const std::string &options = std::string())
  300. {
  301. const char *options_string = 0;
  302. if(!options.empty()){
  303. options_string = options.c_str();
  304. }
  305. cl_int ret;
  306. cl_program program_ = clLinkProgram(
  307. context.get(),
  308. 0,
  309. 0,
  310. options_string,
  311. static_cast<uint_>(programs.size()),
  312. reinterpret_cast<const cl_program*>(&programs[0]),
  313. 0,
  314. 0,
  315. &ret
  316. );
  317. if(!program_){
  318. BOOST_THROW_EXCEPTION(opencl_error(ret));
  319. }
  320. return program(program_, false);
  321. }
  322. #endif // BOOST_COMPUTE_CL_VERSION_1_2
  323. /// Returns the build log.
  324. std::string build_log() const
  325. {
  326. return get_build_info<std::string>(CL_PROGRAM_BUILD_LOG, get_devices().front());
  327. }
  328. /// Creates and returns a new kernel object for \p name.
  329. ///
  330. /// For example, to create the \c "foo" kernel (after the program has been
  331. /// created and built):
  332. /// \code
  333. /// boost::compute::kernel foo_kernel = foo_program.create_kernel("foo");
  334. /// \endcode
  335. kernel create_kernel(const std::string &name) const;
  336. /// Returns \c true if the program is the same at \p other.
  337. bool operator==(const program &other) const
  338. {
  339. return m_program == other.m_program;
  340. }
  341. /// Returns \c true if the program is different from \p other.
  342. bool operator!=(const program &other) const
  343. {
  344. return m_program != other.m_program;
  345. }
  346. /// \internal_
  347. operator cl_program() const
  348. {
  349. return m_program;
  350. }
  351. /// Creates a new program with \p source in \p context.
  352. ///
  353. /// \see_opencl_ref{clCreateProgramWithSource}
  354. static program create_with_source(const std::string &source,
  355. const context &context)
  356. {
  357. const char *source_string = source.c_str();
  358. cl_int error = 0;
  359. cl_program program_ = clCreateProgramWithSource(context,
  360. uint_(1),
  361. &source_string,
  362. 0,
  363. &error);
  364. if(!program_){
  365. BOOST_THROW_EXCEPTION(opencl_error(error));
  366. }
  367. return program(program_, false);
  368. }
  369. /// Creates a new program with \p sources in \p context.
  370. ///
  371. /// \see_opencl_ref{clCreateProgramWithSource}
  372. static program create_with_source(const std::vector<std::string> &sources,
  373. const context &context)
  374. {
  375. std::vector<const char*> source_strings(sources.size());
  376. for(size_t i = 0; i < sources.size(); i++){
  377. source_strings[i] = sources[i].c_str();
  378. }
  379. cl_int error = 0;
  380. cl_program program_ = clCreateProgramWithSource(context,
  381. uint_(sources.size()),
  382. &source_strings[0],
  383. 0,
  384. &error);
  385. if(!program_){
  386. BOOST_THROW_EXCEPTION(opencl_error(error));
  387. }
  388. return program(program_, false);
  389. }
  390. /// Creates a new program with \p file in \p context.
  391. ///
  392. /// \see_opencl_ref{clCreateProgramWithSource}
  393. static program create_with_source_file(const std::string &file,
  394. const context &context)
  395. {
  396. // create program
  397. return create_with_source(read_source_file(file), context);
  398. }
  399. /// Creates a new program with \p files in \p context.
  400. ///
  401. /// \see_opencl_ref{clCreateProgramWithSource}
  402. static program create_with_source_file(const std::vector<std::string> &files,
  403. const context &context)
  404. {
  405. std::vector<std::string> sources(files.size());
  406. for(size_t i = 0; i < files.size(); ++i) {
  407. // open file stream
  408. std::ifstream stream(files[i].c_str());
  409. if(stream.fail()){
  410. BOOST_THROW_EXCEPTION(std::ios_base::failure("failed to create stream."));
  411. }
  412. // read source
  413. sources[i] = std::string(
  414. (std::istreambuf_iterator<char>(stream)),
  415. std::istreambuf_iterator<char>()
  416. );
  417. }
  418. // create program
  419. return create_with_source(sources, context);
  420. }
  421. /// Creates a new program with \p binary of \p binary_size in
  422. /// \p context.
  423. ///
  424. /// \see_opencl_ref{clCreateProgramWithBinary}
  425. static program create_with_binary(const unsigned char *binary,
  426. size_t binary_size,
  427. const context &context)
  428. {
  429. const cl_device_id device = context.get_device().id();
  430. cl_int error = 0;
  431. cl_int binary_status = 0;
  432. cl_program program_ = clCreateProgramWithBinary(context,
  433. uint_(1),
  434. &device,
  435. &binary_size,
  436. &binary,
  437. &binary_status,
  438. &error);
  439. if(!program_){
  440. BOOST_THROW_EXCEPTION(opencl_error(error));
  441. }
  442. if(binary_status != CL_SUCCESS){
  443. BOOST_THROW_EXCEPTION(opencl_error(binary_status));
  444. }
  445. return program(program_, false);
  446. }
  447. /// Creates a new program with \p binary in \p context.
  448. ///
  449. /// \see_opencl_ref{clCreateProgramWithBinary}
  450. static program create_with_binary(const std::vector<unsigned char> &binary,
  451. const context &context)
  452. {
  453. return create_with_binary(&binary[0], binary.size(), context);
  454. }
  455. /// Creates a new program with \p file in \p context.
  456. ///
  457. /// \see_opencl_ref{clCreateProgramWithBinary}
  458. static program create_with_binary_file(const std::string &file,
  459. const context &context)
  460. {
  461. // open file stream
  462. std::ifstream stream(file.c_str(), std::ios::in | std::ios::binary);
  463. // read binary
  464. std::vector<unsigned char> binary(
  465. (std::istreambuf_iterator<char>(stream)),
  466. std::istreambuf_iterator<char>()
  467. );
  468. // create program
  469. return create_with_binary(&binary[0], binary.size(), context);
  470. }
  471. #if defined(BOOST_COMPUTE_CL_VERSION_1_2) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
  472. /// Creates a new program with the built-in kernels listed in
  473. /// \p kernel_names for \p devices in \p context.
  474. ///
  475. /// \opencl_version_warning{1,2}
  476. ///
  477. /// \see_opencl_ref{clCreateProgramWithBuiltInKernels}
  478. static program create_with_builtin_kernels(const context &context,
  479. const std::vector<device> &devices,
  480. const std::string &kernel_names)
  481. {
  482. cl_int error = 0;
  483. cl_program program_ = clCreateProgramWithBuiltInKernels(
  484. context.get(),
  485. static_cast<uint_>(devices.size()),
  486. reinterpret_cast<const cl_device_id *>(&devices[0]),
  487. kernel_names.c_str(),
  488. &error
  489. );
  490. if(!program_){
  491. BOOST_THROW_EXCEPTION(opencl_error(error));
  492. }
  493. return program(program_, false);
  494. }
  495. #endif // BOOST_COMPUTE_CL_VERSION_1_2
  496. #if defined(BOOST_COMPUTE_CL_VERSION_2_1) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
  497. /// Creates a new program with \p il_binary (SPIR-V binary)
  498. /// of \p il_size size in \p context.
  499. ///
  500. /// \opencl_version_warning{2,1}
  501. ///
  502. /// \see_opencl21_ref{clCreateProgramWithIL}
  503. static program create_with_il(const void * il_binary,
  504. const size_t il_size,
  505. const context &context)
  506. {
  507. cl_int error = 0;
  508. cl_program program_ = clCreateProgramWithIL(
  509. context.get(), il_binary, il_size, &error
  510. );
  511. if(!program_){
  512. BOOST_THROW_EXCEPTION(opencl_error(error));
  513. }
  514. return program(program_, false);
  515. }
  516. /// Creates a new program with \p il_binary (SPIR-V binary)
  517. /// in \p context.
  518. ///
  519. /// \opencl_version_warning{2,1}
  520. ///
  521. /// \see_opencl_ref{clCreateProgramWithIL}
  522. static program create_with_il(const std::vector<unsigned char> &il_binary,
  523. const context &context)
  524. {
  525. return create_with_il(&il_binary[0], il_binary.size(), context);
  526. }
  527. /// Creates a new program in \p context using SPIR-V
  528. /// binary \p file.
  529. ///
  530. /// \opencl_version_warning{2,1}
  531. ///
  532. /// \see_opencl_ref{clCreateProgramWithIL}
  533. static program create_with_il_file(const std::string &file,
  534. const context &context)
  535. {
  536. // open file stream
  537. std::ifstream stream(file.c_str(), std::ios::in | std::ios::binary);
  538. // read binary
  539. std::vector<unsigned char> il(
  540. (std::istreambuf_iterator<char>(stream)),
  541. std::istreambuf_iterator<char>()
  542. );
  543. // create program
  544. return create_with_il(&il[0], il.size(), context);
  545. }
  546. #endif // BOOST_COMPUTE_CL_VERSION_2_1
  547. /// Create a new program with \p source in \p context and builds it with \p options.
  548. /**
  549. * In case BOOST_COMPUTE_USE_OFFLINE_CACHE macro is defined,
  550. * the compiled binary is stored for reuse in the offline cache located in
  551. * $HOME/.boost_compute on UNIX-like systems and in %APPDATA%/boost_compute
  552. * on Windows.
  553. */
  554. static program build_with_source(
  555. const std::string &source,
  556. const context &context,
  557. const std::string &options = std::string()
  558. )
  559. {
  560. #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
  561. // Get hash string for the kernel.
  562. device d = context.get_device();
  563. platform p = d.platform();
  564. detail::sha1 hash;
  565. hash.process( p.name() )
  566. .process( p.version() )
  567. .process( d.name() )
  568. .process( options )
  569. .process( source )
  570. ;
  571. std::string hash_string = hash;
  572. // Try to get cached program binaries:
  573. try {
  574. boost::optional<program> prog = load_program_binary(hash_string, context);
  575. if (prog) {
  576. prog->build(options);
  577. return *prog;
  578. }
  579. } catch (...) {
  580. // Something bad happened. Fallback to normal compilation.
  581. }
  582. // Cache is apparently not available. Just compile the sources.
  583. #endif
  584. const char *source_string = source.c_str();
  585. cl_int error = 0;
  586. cl_program program_ = clCreateProgramWithSource(context,
  587. uint_(1),
  588. &source_string,
  589. 0,
  590. &error);
  591. if(!program_){
  592. BOOST_THROW_EXCEPTION(opencl_error(error));
  593. }
  594. program prog(program_, false);
  595. prog.build(options);
  596. #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
  597. // Save program binaries for future reuse.
  598. save_program_binary(hash_string, prog);
  599. #endif
  600. return prog;
  601. }
  602. /// Create a new program with \p file in \p context and builds it with \p options.
  603. /**
  604. * In case BOOST_COMPUTE_USE_OFFLINE_CACHE macro is defined,
  605. * the compiled binary is stored for reuse in the offline cache located in
  606. * $HOME/.boost_compute on UNIX-like systems and in %APPDATA%/boost_compute
  607. * on Windows.
  608. */
  609. static program build_with_source_file(
  610. const std::string &file,
  611. const context &context,
  612. const std::string &options = std::string()
  613. )
  614. {
  615. return build_with_source(read_source_file(file), context, options);
  616. }
  617. private:
  618. #ifdef BOOST_COMPUTE_USE_OFFLINE_CACHE
  619. // Saves program binaries for future reuse.
  620. static void save_program_binary(const std::string &hash, const program &prog)
  621. {
  622. std::string fname = detail::program_binary_path(hash, true) + "kernel";
  623. std::ofstream bfile(fname.c_str(), std::ios::binary);
  624. if (!bfile) return;
  625. std::vector<unsigned char> binary = prog.binary();
  626. size_t binary_size = binary.size();
  627. bfile.write((char*)&binary_size, sizeof(size_t));
  628. bfile.write((char*)binary.data(), binary_size);
  629. }
  630. // Tries to read program binaries from file cache.
  631. static boost::optional<program> load_program_binary(
  632. const std::string &hash, const context &ctx
  633. )
  634. {
  635. std::string fname = detail::program_binary_path(hash) + "kernel";
  636. std::ifstream bfile(fname.c_str(), std::ios::binary);
  637. if (!bfile) return boost::optional<program>();
  638. size_t binary_size;
  639. std::vector<unsigned char> binary;
  640. bfile.read((char*)&binary_size, sizeof(size_t));
  641. binary.resize(binary_size);
  642. bfile.read((char*)binary.data(), binary_size);
  643. return boost::optional<program>(
  644. program::create_with_binary(
  645. binary.data(), binary_size, ctx
  646. )
  647. );
  648. }
  649. #endif // BOOST_COMPUTE_USE_OFFLINE_CACHE
  650. static std::string read_source_file(const std::string &file)
  651. {
  652. // open file stream
  653. std::ifstream stream(file.c_str());
  654. if(stream.fail()){
  655. BOOST_THROW_EXCEPTION(std::ios_base::failure("failed to create stream."));
  656. }
  657. // read source
  658. return std::string(
  659. (std::istreambuf_iterator<char>(stream)),
  660. std::istreambuf_iterator<char>()
  661. );
  662. }
  663. private:
  664. cl_program m_program;
  665. };
  666. /// \internal_ define get_info() specializations for program
  667. BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(program,
  668. ((cl_uint, CL_PROGRAM_REFERENCE_COUNT))
  669. ((cl_context, CL_PROGRAM_CONTEXT))
  670. ((cl_uint, CL_PROGRAM_NUM_DEVICES))
  671. ((std::vector<cl_device_id>, CL_PROGRAM_DEVICES))
  672. ((std::string, CL_PROGRAM_SOURCE))
  673. ((std::vector<size_t>, CL_PROGRAM_BINARY_SIZES))
  674. ((std::vector<unsigned char *>, CL_PROGRAM_BINARIES))
  675. )
  676. #ifdef BOOST_COMPUTE_CL_VERSION_1_2
  677. BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(program,
  678. ((size_t, CL_PROGRAM_NUM_KERNELS))
  679. ((std::string, CL_PROGRAM_KERNEL_NAMES))
  680. )
  681. #endif // BOOST_COMPUTE_CL_VERSION_1_2
  682. #ifdef BOOST_COMPUTE_CL_VERSION_2_1
  683. BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(program,
  684. ((std::vector<unsigned char>, CL_PROGRAM_IL))
  685. )
  686. #endif // BOOST_COMPUTE_CL_VERSION_2_1
  687. } // end compute namespace
  688. } // end boost namespace
  689. #endif // BOOST_COMPUTE_PROGRAM_HPP