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